,这里我和大家说说Java的发展史
世界上并没有完美的程序,因为写程序本来就是一个不断追求完美的过程。同样没有一门语言在一诞生就是完美的,不变的唯有变化。Java诞生至今已经不仅仅是一门语言,背后所涵盖的是一个庞大的技术体系。
网上每隔一段时间就能见到几条“未来X语言将会取代Java”的新闻,此处“X”可以用Kotlin、Golang、Dart、JavaScript、Python等各种编程语言来代入。这大概就是长期占据编程语言榜单第一位的烦恼,天下第一总避免不了挑战者相伴。
在过去二十年Java的发展是孤独求败的,在未来,Java也在迎接着各种挑战,这种挑战来自云原生、容器化、也来自其他设计更完善的语言,相信身怀各种绝技的Java会焕发出更加夺目的光彩,重新攀登另一个高峰。
如果你问我,Java以后会不会渐渐衰落,我的回答是,百分之99会!但是我们的学习不会停止,而且掌握了Java,其他的编程语言学习起来也会如切白菜一样简单容易上手,所以不用太过于担心这个问题
Java是在1991年由SUN公司的James Gosling(Java之父)及其团队所研发的一种编程语言,第一个版本耗时18个月,最开始命名为Oak(一种橡树)。Java现在广泛应用于各种大型互联网应用,其设计的最初动机主要是平台独立(即体系结构中立)语言的需要,可以嵌入到各种消费类电子设备(家用电器等),但市场反应不佳。
随着1990年代互联网的发展,SUN公司看到了Oak在互联网上的应用场景,在1995年更名为Java(印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名),随着互联网的崛起,Java逐渐称为重要的Web应用开发语言。Java的发展可以主要看JavaWeb的发展,Java也见证了互联网的发展过程。
发展至今,Java不仅是一门编程语言,还是一个由一系列计算机软件和规范组成的技术体系,Java 是几乎所有类型的网络应用程序的基础,也是开发和提供嵌入式和移动应用程序、游戏、基于 Web 的内容和企业软件的全球标准。
从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Java 无处不在!
说到Java自然离不开JDK、JVM、JRE,三者有什么关系。
● JDK(Java Development Kit)Java开发工具包,包含Java语言、Java虚拟机、Java类库,是支持Java程序开发的最小环境。
● JVM(Java Virtual Machine)Java虚拟机,运行于各种操作系统Linux,Windows,Solaris等之上,执行编译好的Java字节码class文件。
● JRE(Java Runtime Environment)Java运行时环境,包含JavaSE中核心类库API和Java虚拟机,简单理解为JVM+核心类库API。
● 1991年4月,Java之父James Gosling带领绿色计划(Green Project)项目启动,定位于消费电子产品(机顶盒、冰箱、收音机)运行架构的Oak语言诞生,这也是Java的前身,但是市场反响一般。
● 1995年5月23日,随着互联网浪潮在1995年兴起,Oak迅速蜕,Java语言诞生,在SunWorld大会上发布Java1.0,第一次提出Write Once,Run Anywhere的口号。
● 1996年1月23日,JDK1.0发布,纯解释型的Java虚拟机(Sun Classic VM)、Applet、AWT等诞生。
● 1996年4月,十个最主要的操作系统和计算机供应商声明将在其产品中嵌入Java技术,
● 1996年5月底,Sun于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java开发者每年一度的技术盛会。
● 1996年9月,已有大约8.3万个网页应用了Java技术来制作。
● 1997年2月19日,Sun公司发布了JDK1.1,代表技术:JAR文件格式、JDBC、JavaBeans、RMI等,Java语法也进行了增强,内部类(Inner Class)和反射(Reflection)出现。
● 1998年12月4日,JDK1.2发布,这是一个里程碑式的重要版本,工程代号为Playground(竞技场),这个版本代表性技术非常多,如EJB、JavaPlug-in、Swing、JavaIDL等,还有使用极为频繁的Collections体系工具类等,并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)即时编译器,后续还发布了JDK1.2.1和JDK1.2.2两个小版本升级。在JDK1.2中曾经共存过ClassicVM、HotSpotVM、ExactVM三个虚拟机,其中HotSpot是作为附加程序提供。也是在这个版本中Sun开始拆分对应的Java产品线,Sun在这个版本中把Java技术体系拆分为三个方向:
○ 分别是面向桌面应用开发的J2SE(Java 2 Platform,Standard Edition)
○ 面向企业级开发的J2EE(Java 2 Platform,Enterprise Edition)
○ 面向手机等移动终端开发的J2ME(Java 2 Platform,Micro Edition)
● 1999年4月27日,HotSpot虚拟机诞生,HotSpot最初由Longview Techno-logies公司研发,后来在1997年被Sun公司收购,后来它成为JDK 1.3及之后所有JDK版本的默认Java虚拟机。
● 2000年5月8日,工程代号为Kestrel(美洲红隼)的JDK 1.3发布。JDK 1.3的改进主要体现在Java类库上(如数学运算和新的Timer API等),此外一直作为扩展服务的JNDI服务也开始作为一项平台级服务被提供,还有基于CORBA IIOP协议来实现通信段RMI也出现了。
● 2001年5月17日,JDK1.3的修订版JDK1.3.1发布,工程代号Ladybird(瓢虫)。从JDK1.3开始,Sun公司维持着稳定的开发节奏,大概每个两年发布一个主要版本,期间发布的各个修订版本以昆虫作为工程代号。
● 2002年2月13日,JDK 1.4发布,工程代号为Merlin(灰背隼)。JDK 1.4是标志着Java真正走向成熟的一个版本。Compaq、SAS、Fujitsu、Symbian、IBM等一众大公司参与功能规划,甚至实现自己的独立发行版本。哪怕在二十年后的今天一些主流功能也可以在JDK1.4上运行,这个版本的主要代表技术包含正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器等等。
● 2002年9月16日,工程代号为Grasshopper(蚱蜢)的JDK1.4.1修订版发布。在这一年前后微软平台的.NET Framework发布,至此Java平台和.NET平台的竞争开始拉开了序幕。但似乎Java的开源策略更胜一筹,终于在2014 年 11 月 12 日,微软正式宣布了.NET Core 的开源。
● 2003年6月26日,工程代号为Mantis(螳螂)的JDK1.4.2修订版发布。
● 2004年9月30日,JDK 5发布,工程代号为Tiger(老虎),Sun公司从这个版本开始放弃JDK 1.x的命名方式,将产品版本号修改成了JDK x,JDK1.2以来Java语言在语法上的改动都不大,该版本在语法易用性上做出了非常大的改进,如自动装箱、泛型、动态注解、枚举、可变长参数、foreach等。此外改进了Java的内存模型(Java Memory Model,JMM)、提供了java.util.concurrent并发包(由Doug Lea大师带Java进入了并发时代)等,JDK 5是官方声明可以支持Windows 9x操作系统的最后一个版本。
● 2006年11月13日,JavaOne大会上,Sun公司宣布计划要把Java开源,随后在一年多的时间内,陆续的将JDK各部分在GPL V2协议下公开源码,随后并建立了OpenJDK组织对这些源码进行独立管理,除了极少部分的产权代码,OpenJDK几乎拥有了SunJDK 7中的全部代码。
● 2006年12月11日,JDK6发布,工程代号为Mustang(野马)。在这个版本中,Sun公司终结了从JDK 1.2开始已经有八年历史的J2EE、J2SE、J2ME的产品线命名方式,启用Java EE 6、Java SE 6、Java ME 6的新命名来代替。在JDK 6中提供了众多改进,如通过Mozilla JavaScript Rhino引擎提供初步动态语言支持,提供编译器注解处理器(Annotation Processor这也是Lombok的原理,通过注解生成模板代码)和微型HTTP服务器API,以及对虚拟机内部锁、同垃圾收集、类加载机制等方面进行了大量优化改动。在JDK 6发布以后由于代码的复杂化,Java开源、开发JavaFx、世界经济危机以及Oracle对Sun的收购提案等原因,Sun公司内忧外患自顾不暇,原本稳定的开发进度也受到了很大的影响,使得JDK 6的生命周期也持续了很久,一共发布了211个更新补丁,最终版本为Java SE 6 Update 211,于2018年10月18日发布。
● 2009年2月19日,工程代号为Dolphin(海豚)的JDK 7发布,这是其第一个里程碑版本,按照规划,共有十个里程碑版本发布,最后一个里程碑版本发布与2010年9月9日,由于各种原因JDK 7没有按照原计划完成。JDK 7开发阶段Sun公司在技术竞争和商业竞争中都深陷泥潭,已经无力推动开发进展,为了尽快完成JDK 7的发布,因此裁掉了大部分原定的功能,对于原定的Lambdax项目、Jigsaw项目、动态语言支持、Gabage-First垃圾收集器、Coin项目只匆匆交付了处于Experimental状态的G1垃圾收集器(直到2012年4月的Update 4中才开始正式商用),其余项目延期到JDK 8中。Oracle从JDK 7开始进行接手,迅速展现出了其极具商业化的处世风格,面对Java中使用最广泛的Java SE免费产品线,定义了一套新的商业版产品Java SE Support ,此外JDK 7计划维护到2022年,已经面向付费用户发布了211个补丁,最新版本为JDK 7 Update 211。
● 2009年4月20日,Oracle宣布正式以74亿美元的价格收SUN公司,一代巨头由此没落,Java商标正式划归Oracle所有,Java语言本身并不属于哪间公司所有,它由JCP组织进行管理。此外Oracle还收购了BEA公司,JavaEE服务器Weblogic就是该公司的产品。
● 2011年7月28日,JDK7发布,做出的改进:提供新的G1收集器、加强对非Java语言的调用支持、可并行的类加载架构等。
● 2014年3月18日,Oracle公司发布JDK 8,从此使用JEP(JDK Enhancement Proposals)来定义和管理纳入新版JDK发布范围的功能特性,JDK 8中实现了JDK7中定义并且未完成的功能,其中也有被延期到JDK 9的Jigsaw模块化功能。
○ JEP 126 Lambda函数表达式支持
○ JEP 104 内置Nashorn JavaScript引擎
○ JEP 150 新的时间日期API
○ JEP 122 移除HotSpt永久代
● 2017年9月21日,Oracle公司发表 JDK 9,这其中较为显著的功能就是在JDK 7时期已经规划的Jigsaw模块化功能,为何屡次发布都未能如约而至,前期可能是技术埋坑,后面遭到了以IBM和RedHat联合的等JCP委员抵抗,否决模块化提案,这种做法无疑是革了模块化支持本身就比较好的IBM的命,面对如此抵抗,Oracle丝毫没有退让,宁愿摒弃JSR独立研发,也要推行Jigsaw的发展,如果成真,想必Java也会面临如Python2和Python3的巨大不同,好在最终达成一直协议,Java还是那个完整的Java。JDK 9还提供了JS Shell、JLink、JHSDB等增强。JDK 9之后,Java也以更加敏捷的交付方式如期而至,每年的3月和9月发布一个版本,美6个月发布一个版本,每三年一个LTS版本,目的是避免众多功能交付在一个捆绑JDK的风险,并且提出了孵化器模块(Incubator)和预览特性(Preview)两个概念。也是在这个版本中CMS开始被废弃。
● 2018年3月20日,Oracle公司发布JDK 10,主要对内部进行重构,统一源仓库,统一垃圾收集器接口,统一即时编译器接口(引入Graal几时编译器,这里也埋下一个伏笔),这些改进对于用户并不明显,但对后期的版本打下了良好的基础。
● 2018年3月,同样发生了比较重要的一件事,Oracle正式宣布Java EE成为历史名称,曾经拥有着无数光辉的Java EE产品线(至今仍使用较为广泛的JDBC、JMS、Servlet等组件)被Oracle扫地出门,全部打包赠送给Eclipse基金会,并且不能使用Java商标,并且更名为Jakarta EE。
● 2018年10月,自1996年以来每年一度的已经举办了22年的JavaOne大会,没有人预测到这也是最后一届,同年6月Java Mission Control的开发团队也被Oracle解散。
● 2018年9月25日,JDK 11发布,这也是一个LTS(long-term support)版本,包含17个JEP,同时被引入的还有ZGC这样革命性的垃圾收集器,好比G1的诞生,比G1又更具神秘感。同时Oracle也调整了JDK的授权许可证,把以前的商业许可证授权给OpenJDK,官方宣布同时发布两个JDK,一个是Oracle OpenJDK,一个是OracleJDK,共享大部分源码近乎一致,个人均可免费使用,OpenJDK有半年的更新支持,OracleJDK商用必须付费,且支持三年的更新。因此Java收费纯属谣言,商业用户如果想使用最新的版本支持就必须付费。
● 2019年3月20日,JDK 12发布,RedHat接手了OpenJDK 8和OpenJDk 11的管理和维护权。在JDK 12中包含了8个JEP,主要有Switch表达式和JMH测试套件,最引人注目的就是Shenandoah垃圾收集器,作为首个在JDK 7以后非Oracle开发的垃圾收集器,其目标与ZGC一致,这种竞争关系,立马得到了Oracle的抵制,在OracleJDK中剔除代码,因此Oracle JDK和OpenJDK的隔离性又如历史在JDK9中开始重演,至于后续Java的发展,以及迎接的挑战也是任重而道远,这取决于Oracle的产品线的定制和JCP的决策了。
● 2019年在9月17日,JDK 13发布,这个版本主要通过改善Java SE平台和JDK的性能,稳定性和安全性来提高开发人员的生产力。共包含了5个JEPs和一个Unicode 12.1的支持总共6大主要新特性。
○ Support for Unicode 12.1 java.lang.Character支持Unicode Character12.1库,相比12.0库新增554个字符。
○ JEP 351: ZGC Uncommit Unused Memory ZGC增强了对未使用堆内存返还操作系统的能力,ZGC对堆内存的控制能力也从4TB提升至16TB,这个版本对ZGC进行了性能的增强。
○ JEP 350: Dynamic CDS Archiving 动态归档能力,HostSpotVM对AppCDS的一个增强。
○ JEP 354: Switch Expressions (Preview)switch表达式的引入,在后面的JDK 17中又继续对其功能进行了增强。
○ JEP 355: Text Blocks (Preview)增加了Java语言对文本块的支持,但这只是作为一个预览性质的功能,通过""" """来放置多行代码。
○ JEP 353: Reimplement the Legacy Socket API 重新实现了java.net.Socket and java.net.ServerSocket 类提供的APIs。
● 2020年3月17日,JDK 14发布,这个版本主要是对JDK历史版本的一些增强,也引入了一些新增的功能.
○ JEP 359: Records (Preview) 新增了java.lang.Record类,Record是一种轻量级的class,可以看做是数据结构体。Java作为面向对象的语言诞生以来,在大型项目中的优势就体现出来了,但是也有一点不好,过于繁琐,一个POJO JavaBean必须包含get、set等方法,Record主要就是解决这类问题的,类似于Lombok的功能。
○ JEP 365: ZGC on Windows
○ JEP 364: ZGC on macOS
○ JEP 345: NUMA-Aware Memory Allocation for G1 G1的NUMA感知内存分配。这样可以提高使用非均匀内存体系结构(NUMA)的大型计算机的性能。
○ JEP 349: JFR Event Streaming 通过启用工具以异步方式订阅Java Flight Recorder事件,这可以对JVM进行更实时的监视。
○ JEP 363: Remove the Concurrent Mark and Sweep (CMS) Garbage Collector,CMS作为一款主打老年代的并发垃圾收集器,虽然历任JDK中都没有被设置为默认的垃圾收集器,但是在解决STW问题时也是有着举足轻重的地位的,从JDK 7开始筹备到JDK 9作为默认的G1垃圾收集器,一度被认为CMS的升级版,在次CMS也开始走下历史舞台。
○ JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination 随着每一代JDk中对垃圾收集器的升级以及新的垃圾收集器的引入,ParallelScavenge + SerialOld(Oracle指出很少有人使用)组合的GC也被弃用了,并在不久的将来被移除,完成了自己的历史使命。
● 2020年9月15日,JDK 15发布,按照规划路线,JDK 14也停止更新,JDK 15虽然不是LTS版本,但也引入了一些开创性的功能和对早期版本功能的一些优化。
○ JEP 371: Hidden Classes,
○ JEP 378: Text Blocks,在JDK 13已经发布的二次预览版本,对于文本块的支持非常友好。
○ JEP 377: ZGC A Scalable Low-Latency Garbage Collector (Production),这个支持应该算是比较重要的,相比于JDK 11作为实验性质而引入的ZGC,在这两年中ZGC现在已准备好用于生产,不再标记为实验特征,可以直接使用 -XX:+UseZGC开启ZGC,不再需要XX:+UnlockExperimentalVMOptions额外的配置。需要注意的是在OracleJDK中使用的是ZGC,而在OpenJDK中使用的是Shenandoah GC,使用命令-XX:+UseShenandoahGC开启。
● 2021年3月16日,JDK 16发布,这部分依旧是一些功能的优化升级。
○ JEP 389: Foreign Linker API (Incubator)提供静态键入的纯-java访问本机代码的API。
○ JEP 393: Foreign-Memory Access API (Third Incubator)提供了操作外部内存能力的API。
○ JEP 380: Unix domain sockets java.nio.channels, SocketChannel和ServerSocketChannel新增了对UNIX套接字的支持。
○ JEP 338: Vector API (Incubator) 提供孵化器模块的初始迭代,JDK.INCUBATOR.Vector,以表达在运行时可靠地编译的向量计算到支持的CPU架构上的最佳矢量硬件指令,从而实现对等效标量计算的卓越性能。这一点在JDK 17上持续增强。
○ JEP 376: ZGC Concurrent Stack Processing,ZGC的并发标记,不同于CMS的标记,ZGC的标记只有三个阶段,且每一个阶段的操作,无论是标记还是清理都是并发操作,大大降低了STW的时间,几乎零延时。这也算是Java在垃圾回收中比较开创性的变革。
○ JEP 387: Elastic Metaspace,JDK16对元数据区切分为更小的内存块,并将不再使用的内存快速返还给操作系统,对于频繁加载和卸载类的应用来说这一优化可以产生大量的空闲内存,提升整个JVM的性能。
○ JEP 397: Sealed Classes (Second Preview),对JDK内部方法提供强制的封装,在JDK 17依然进行了升级优化。
○ JEP 395: Records,从JDK 14作为预览版被提供在,这里已经升级为正式版功能。
○ JEP 392: Packaging Tool,新的打包工具,在JDK 14中通过JEP343被提案,在JDK 15中被孵化,在JDK 16中被提升为正式支持使用,通过jpackage命令支持native可执行程序打包。
● 2021年9月14日,JDK17发布,这也是在JDK 11之后的下一个LTS版本,JDK 17也是Java六个月发布节奏下的最新的长期支持(LTS)发布,主打安全、性能、稳定为特性,并且官方计划支持到2029年9月。在这个版本中包含了14个JEPs更新。
○ JEP 356: Enhanced Pseudo-Random Number Generator 伪随机数增强器
○ JEP 391: macOS AArch64 Port 新平台的支持
○ JEP 410: Remove the Experimental AOT and JIT Compiler 移除了实验性质的AOT和JIT编译器
○ JEP 411: Deprecate the Security Manager for Removal 弃用安全管理器
○ JEP 406: Pattern Matching for switch (Preview) switch表达式,这可能是一个让switch翻身的功能。
○ JEP 412: Foreign Function and Memory API (Incubator) 外函数和内存相关的API,在JDK 14和JDK 15中引入的孵化API,使Java程序能够与Java运行时之外的代码和数据互操作,通过有效地调用外部函数(即,JVM之外的代码),并通过安全访问异物,这些API使Java程序能够调用本机库并进入本机数据而不提供Java本机接口(JNI)的脆性和复杂性。
○ JEP 414: Vector API (Second Incubator)允许表达在运行时可靠地编译的向量计算以支持的CPU架构上的优化矢量指令,从而实现优于等效标量计算的性能
其实在20世纪90年代,那个时候互联网才刚刚兴起不久,在当时的编程圈子里.C/C++是绝对的王者,M国有个大佬,想要研究一个东西,叫做"智能面包机",他带着他的团队用C/C++来开发,但是后来发现他的队员好像有些搞不定,所以他想弄一个更简单一点的编程语言来代替C++用来开发面包机.
后来面包机做没做成不知道,但他弄出来的这个语言倒是火了,它便是Java.这个大佬所在的公司便是Sun.公司初始对Java的定位是搞嵌入式开发.
后来,大佬们盯上了刚刚兴起的互联网,他们便使用Java嵌入到浏览器当中,在页面上和用户进行交互,这正是"前端开发",那个时候叫做Applet(现在在图书馆里翻一些比较老的教材,还能看到这个词的影子)
后来Java逐渐崛起,成为了一个非常主流的编程语言.
这时,一个人暗中观察,一看Java这么火,为了蹭热度,他就把自己做的语言起名字叫做JavaScript,它干的事情还和Java差不多
还有一些语言也能进行前端开发,比如MS VBScript 也能用于前端开发
当年的前端圈子也是群魔乱舞的状态
最开始很牛逼的浏览器叫做网景,后来就是IE,由于IE和Windows捆绑销售,IE逐渐一统江湖
前端开发的编程语言都是运行在浏览器上的
然而这是,MS就做出了一个违背祖宗的决定,在IE上全面封杀Java,这一举动,让Java一路从天堂跌入地狱
无奈,VBS也是个阿斗,反而被JavaScript抢占了先机,从而成为了前端开发的第一语言
但虽然如此,Java也并没有从此一蹶不振,它又开始寻找新的出路
L:Linux
A:Apache
M:MySQL
P:PHP(PHP一度认为自己是世界上最好的语言,这句话出现在它们的官网上)
随着21实际的到来,此时,乔布斯发布了苹果手机,从此开启了移动互联网的时代,IOS和安卓崛起,诺基亚等功能收集,在短短几年之内也就从霸主沦落到要变卖总部大楼
同时,JavaME这台技术体系,也瞬间就凉凉了
Java再一次从天堂跌到地狱.
但Java这次依旧没有沉沦,并且安卓向Java抛出了橄榄枝.
安卓,谷歌内部支持了使用Java作为安卓的原生开发语言(当然C++也可以)
这一波程序员就涌入了安卓市场,一下子就把安卓的生态给打通了,进入了良性的发展循环,市场份额奋起直追,很快就超越了苹果,Java也成为了移动端开发的大哥大.
后端开发这个领域.原来PHP这样的"服务器选渲染"这样的实现方式逐渐没落,新的"全后端分离"的开发方式也逐渐崛起
Java的Spring全家桶也随之崛起,Java一句超越PHP成为了后端的大哥大.而这些也使Java成为了编程语言排行榜的No.1而且霸榜多年
计算机发明者约翰·冯·诺依曼。计算机是20世纪最先进的科学技术发明之一,对人类的生产活动和社会活动产生了极其重要的影响,并以强大的生命力飞速发展。它的应用领域从最初的军事科研应用扩展到社会的各个领域,已形成了规模巨大的计算机产业,带动了全球范围的技术进步,由此引发了深刻的社会变革,计算机已遍及一般学校、企事业单位,进入寻常百姓家,成为信息社会中必不可少的工具。计算机的应用在中国越来越普遍,改革开放以后,中国计算机用户的数量不断攀升,应用水平不断提高,特别是互联网、通信、多媒体等领域的应用取得了不错的成绩。1996年至2009 年,计算机用户数量从原来的630万增长至6710 万台,联网计算机台数由原来的2.9万台上升至5940万台。互联网用户已经达到3.16 亿,无线互联网有6.7 亿移动用户,其中手机上网用户达1.17 亿,为全球第一位。
推荐书籍:<计算机简史>

- CPU内部本质上是由一大堆的门电路构成
- CPU内部的继承程度越高,就认为计算机的能力越强
- CPU上面还包含了寄存器,可以存储一些运算的中间结果
- CPU执行程序的过程,大概是取指令,解析指令,执行指令
内存:存储空间小,访问速度快,贵,断电后数据丢失
外村:存储空间大,访问速度慢,便宜,断电之后数据不丢失
针对存储空间:
硬盘>内存>>CPU
针对数据访问速度
CPU>>内存>硬盘
- 对下管理各种硬件设备
- 对上给各种软件提供稳定的运行环境

操作系统是一个搞管理的软件,还要管理很多其他的东西
比如内存管理,文件管理,设备管理…进程管理~


一个可执行文件,是静态的.当我们双击运行的时候,操作系统就会把这个可执行文件中的关键信息加载到内存中,并且开始运行里面的代码,就会形成一个进程
- 我们在访问一些病毒网站的时候,十有八九会让你下载一些可执行程序,这些程序十有八九就是病毒,如果只是单纯下载下来,一般来说问题不大,但是如果一旦运行就歇菜了.
- 那么有没有什么办法,我们想上这样的网站,又不想中毒>?
- 确实有,那就是虚拟机软件
- 使用软件,虚拟出来一个计算机,可以在这个虚拟的计算机里面安装操作系统,在虚拟的计算机里访问各种网站,安装运行各种程序,都不会影响到你真实的物理计算机了.

大家要主义区分,进程和程序(可执行文件)之间的区别.
如上任务管理器中框出来的就是一个进程,QQ跑起来的模板,是动态的,被加载到内存中的
如上,这是一个可执行文件,是静态的,躺在硬盘里面的,一个计算机的硬盘上面可能会躺着很多的可执行文件,同一时刻,可能只有一小部分在运行(变成了进程)
进程管理:一个操作系统上,同时跑着这么多的进程
操作系统就需要把他们都安排明白了
怎么管理呢?
- 先去描述:使用一个类/结构体,(进程管理是操作系统内核的功能,操作系统又是C语言实现的)把这个东西有啥特征,都表示出来(C语言的结构体就是初级的类)
- 再组织:使用一个数据结构,把很多个这样的对象/结构体给整理到一起
操作系统的定位:
PCB:进程控制块
就是一个结构体,这个结构体里包含了一些表示进程的核心信息
操作系统内核中,就把若干PCB串成了一个双向链表
PCB里面都有啥信息?(最好的办法还是看看操作系统内核的源码)
- 进程有个身份标识,叫做pid
- 还有个内存指针:操作系统把一些必要的数据加载到内存中
(有些是要运行的指令–代码)
(有些是运行时依赖的数据–全局变量)
内存指针就描述了该进程的内存中那些部分是指令,哪些部分是数据
- 文件描述符表:表示当前进程都打开了哪些文件
C语言在代码中打开一个文件用fopen
就会在进程的文件描述符表里给这个文件分配一个表项
该文件表述符可以理解为顺序表,每个元素就代表一个打开的文件,对应的数组下标就是"文件描述符"
以上描述了进程持有哪些系统的资源,
我们也把也进程认为是操作系统中"资源分配"的基本单位!
进程中还有一组比较关键的属性,是用来实现进程的调度的(通俗点讲就是调用)
本质问题,当前的计算机,CPU是优先的,但是进程数量比较多的,
CPU核心数只有6核
进程数量却非常非常多,几十个上百个
操作系统是要做到尽可能的公平,让每个狼都有吃肉的机会,这个时候就需要进行调度
CPU的轮转速度其实是非常快的
CPU主频是1.9GHz 1s有19亿个时钟周期,是时间片在轮转
- 因此人感知不到这样的轮转,站在宏观角度来看,就好像这些进程都在同时执行一样,但是微观上并不是同时,而是"轮转"的方式占用CPU执行-----并发式的执行. 这属于是宏观上同时进行,但微观上不是同时进行的
- 由于CPU上有多个核心,每个核心上都可以跑一个进程.某一个时刻两个进程就是在两个CPU核心上同时执行的.----并行式执行. 这是宏观上同时执行,微观上也是同时执行
实际开发中,其实并不会对这两个概念做出明确的区分(从人的宏观角度看,其实看不出来区别)所以往往使用"并发"概括表示"并发"和"并行"
称为"并发编程"
好,我现在举一个亲身经历过的事情,来帮助大家来理解多进程与并发
首先,有一个长得挺好看的女生叫做小灵,她的追求者很多,
虽然林子大什么鸟都有,但她的这些追求者中,没有人同时有钱长得帅成绩好
所以这个女生决定同时谈多个对象.我们假设出三个对象
小张:有钱但是渣
小金:长得帅成绩也很好
小葛:没有小张有钱,没有小金长得帅,但他是恋爱脑,是个舔狗
因为担心人设崩塌,我们的小灵为了维持好自己完美的人设口碑,不能让小张,小金,小哥之间有任何交集
我们称小灵为时间管理大师,她将制作规划出一个时间表,这个时间表就像是课程表,规划出什么时间和谁去约会看电影吃饭
周一:她和小张出去逛万达广场,买了包包
周二:她和小金出去吃了顿饭,吃完饭去海边玩
周三:她和小葛一起去自习室
这个时候,小灵就相当于一个CPU,小张小金小葛就是三个进程,在上述这个时间表的安排下,小灵在和三个人谈恋爱,就好像三个进程都在CPU上并发的执行,
这里,我们要介绍一下进程的调度主要涉及到的进程的一些关键信息.
- 进程的优先级
- 这里就相当于小灵在安排时间表的时候,先把时间安排给谁,后把时间安排给谁.
- 进程安排的优先级规定关乎小灵的个人体验,也就是CPU的执行效率
- 小灵的择偶标准是有钱/长得帅->有钱->长得帅->成绩好,所以她的时间表安排就有一个优先级,优先给有钱b安排时间,所以把一整周的时间都给有钱比,给这个有钱b小张最好的体验,其次再给帅哥小金安排时间,至于舔狗小葛,就看剩下来有没有时间了.
- 进程的状态
- 安排时间表的时候要考虑到每个人的特定状况
- 对于进程来说也一样,有很多状态
- 其中进程的状态最典型的就是:
- 就绪状态:进程是准备就绪,随时可以上CPU执行
- 阻塞状态:进程在等待某个任务完成(读写磁盘),完成之后才能上CPU,完成之前,就没法继续执行
- 正常情况下,有钱比小张,帅哥小金,舔狗小葛都是就绪状态(意思就是小灵随便安排时间,他们都是随叫随到),
- 但如果有钱b小张有一天不在(相当于进入阻塞状态),此时小灵就没法给小张安排时间,就没法跟小张约会了.
- 进程的记账信息
- 小灵在安排时间表的时候,需要考虑到一些历史的信息(也就是以往的安排)
- 如果连续好几个礼拜都没有去安排给舔狗小葛的时间,
- 一看统计数据,给小葛安排的时间太少了,小灵可能就要失去这个小可爱了.
- 所以在下一周可能会多排一点点时间给小葛.
- 操作系统也是如此,它在安排进程的时候,也会记录每个进程以往在CPU上执行的时间
- 如果发现某个进程被安排的时间太少,就会适当得调整策略
- 这里不一定是以执行时间为单位,也有可能是以执行的指令数为单位
- 进程的上下文
- 对于继承来说,上下文,具体指的就是CPU里面寄存器的一堆值,
- 上下文就会在进程被切除CPU的时候把寄存器的状态保存到PCB里面(内存)
- 下次进程回到CPU上就把PCB里的上下文信息读取出来,恢复到CPU寄存器中
- 这里简单举个例子,某一次,CPU小灵和进程1小张说好了,两周以后,让小张带她去夏威夷旅游.
- 又有一次,小灵和帅哥小金在一起的时候,和他说好了,下次见面的时候小金会给她带个小礼物.
- 如果没有进程的上下文,小灵就搞不清和谁做了什么约定,所以就有可能会对着帅哥小金说:夏威夷那边儿准备的怎么样了,这个时候,聪明的小金就会察觉出什么,然后小灵就会被曝光了,对应CPU处理这个进程就处理错误了.
- 为了避免出现这种穿帮的情况,小灵就需要记录好每次约会之后的一些关键信息,尤其是这次约会还没处理完的事情,要下次和同样的对象处理完,
- 那么下次再去处理的时候,小灵就需要明确的记录好当前处理的进度,这样下次约会的时候就可以从上次的结果中继续往下进行了.
- 进程在调度的时候也是一样,进程很可能执行了某个操作,执行一半就被调度走了.
- 过一段时间,进程还是要回来的,回来之后就需要从上次执行到底的位置继续往下进行执行
- 这里也可以有另外一种理解,即为 **存档和读档 **
- 存档保存的信息,就是上次退出之前的游戏状态,这个游戏转台就是上下文
和进程非常相关的概念
进程的虚拟地址空间
进程需要使用一些系统的资源,其中内存资源就是一个很关键的资源

这里我用稍微通俗一点的语句给大家讲解一下:
首先,我们的CPU运作时,CPU中有一块空间,叫做寄存器,它的运行速度是最快的,但同样空间很小,
然后是内存,PCB所存储的进程就被安排在内存中,
那么我们现在的内存不够了,程序运行不过来了.导致运行内存爆满的原因有以下几个原因:
- 内存空间不隔离.我们在早期的程序都是直接访问内存的,同样也能够访问到相邻的地址,所以恶意程序就可能会利用这一点让程序不小心访问到它,恶意程序就可以借此篡改其他程序的数据.
- 内存使用效率低,因为运行程序的时候,需要将整个程序全部读入到内存中,其实其中很多内容并不会访问到,反而占着茅坑不拉屎,浪费了许多运行内存空间
- 运行地址不确定,早期程序使用汇编来编写,读取数据一般通过地址硬编码.
- 不可同时运行总没存超过128m的程序(这个不一定,可能有差异)
那么我们现在可以通过"虚拟内存"来优化内存,让进程所占用的内存空间排布更加优化.
- 首先我们的程序(比如一行行代码)都会被编译器编译成一条条指令,那么指令就是要连续一条一条执行下去的,然后一条指令也对应多条进程(PCB),这些进程被系统串成了一个类似于链表的东西,以此来执行这条指令,那么我们纵然可以一股脑把这些多条指令对应的进程全部放入内存中,但不过这样对于进程并发来说并不是很好的选择,因为调度器在调度进程执行的时候,并不是按照固定的顺序来的,所以不同时间内存中的指令应该是不同的,所以我们可以把一个程序拆成多个指令,然后这些指令可以灵活得按照调度器调度的顺序或者其他方式灵活调整存储在内存中的位置,这样并发执行进程就会快很多,而且内存的使用效率也会大大增加,从而多出一定的内存空间
- 那么这时就出现了一个问题,既然程序的运行是需要连续性的,你执行到一条指令,但是下一条指令你却不知道在哪里了,这是个问题.
- 那么解决方法是,引用额外的硬盘空间,用硬盘空间来开辟出一个对进程在内存中地址的映射表,我们称这块在硬盘上的空间为虚拟内存,那么进程在执行的时候,就可以根据这个虚拟内存的映射表,连接上不连续的内存空间,从而通过额外的调用硬盘空间来解决内存空间占用不连续的问题.
👆因为虚拟地址空间(即虚拟内存),进程就有了一个重要的特性:隔离性!
一个进程的运行一般也不会影响到另一个进程,尤其是一个进程崩溃也不会影响到另外一个进程
那么这里又会出现一个问题,如果每个进程都有一个"虚拟地址空间".那一个系统里面进程又那么多,如果把这些虚拟地址空间再加到一起,比物理内存大很多,可怎么办呢?
- 我认为,硬盘空间的价值是远远没有内存空间大的,所以有舍有得,利大于弊
- 而且虽然系统里面的进程很多,但实际上同一时刻执行的进程其实没几个!!
- 即使同一时刻,有好几个进程在跑着,这些进程也并不是把所有的虚拟地址空间的内存都用上了
- 假设同时是6个进程在跑,很可能每个进程只用了1M的内存空间,虽然每个进程的虚拟空间很大,但是实际上使用的内存其实只有一小部分
- 物理内存只需要把真是使用的这部分内存数据给表示出来就好了
- 极端情况下,确实同时跑的这几个进程同时吃了很多的真实内存,从而导致我们的物理内存空间不够用了(如果出现这种情况,就是bug了,我们就需要想办法优化一下内存的占用,或者扩容换一个内存更大的机器)
我们所说的服务器开发,服务器程序可是非常吃内存的.
那么进程通过虚拟内存引入了隔离性,确实让系统更加稳定了,但是也有别的问题随之出现,
如果多个进程之间想要相互配合工作的话,这样的隔离性反而适得其反.
所以聪明的大佬们就在操作系统中又引入了进程间通信的概念
在隔离性的前提下,在进程所存储的内存里开了个口子,能让多个进程之间能够相互通信.
操作系统提供的进程间通信方式有很多种,但是本质上都是一样的
弄一个多个进程之间都能访问到的公共资源,借助公共资源来进行进程之间的通信,
操作系统(Operation System, OS) 是指控制和管理整个计算机系统的硬件和软件资源,并合理的组织和调度计算机的工作和资源的分配,以提供给用户和其它软件方便的接口和环境,它是计算机系统中最基本的系统软件。
这里的用户是可以直接和操作系统直接进行交互的,但是大多数情况下都是通过应用软件与操作系统进行交互.硬件指的是CPU,内存,硬盘等资源
操作系统说明:

我们可以先思考一下:
我们以植物大战僵尸为例:
step1:找到安装目录D:\植物大战僵尸\PlantsVSZombies
step2:双击PlantsVSZombies.exe
step3:植物大战僵尸运行中
step4:开始游戏
在第一步中,我们所找到的目录,是操作系统提供的文件管理共嗯那个
一个进程是一个程序的执行过程,执行之前需要将程序放到内存中,所以第二步是操作系统提供的存储管理
一个进程要能正常的往下运行,需要分配CPU,所以第三步是操作系统提供的处理机CPU
植物大战僵尸能够播放声音是因为调用了音频等设备,所以第四步是操作系统提供的设备管理

作为用户和计算机硬件之间的接口,操作系统给我们提供了:
- 命令接口:允许用户直接使用
- 程序接口:允许用户通过程序间接使用
- GUI:线代操作系统中最流行的图形用户接口
其中命令接口和程序接口统称为 用户接口
示例:
- 联机命令接口:用户说一句,系统做一句,比如在命令提示行中允许time命令,就会和系统产生交互行为.
- 脱机命令接口:用户说一堆,系统做一堆,就是处理多个命令(批处理命令)
- 程序接口:如一些.dll的文件,只能通过用户程序简洁实用,该调用过程称为系统调用
- GUI:比如删除文件可以直接拖拽到回收站,而不用输入命令
没有任何软件支持的计算机叫做裸机.在裸机上面安装操作系统,可以提供资源管理功能和方便用户的服务功能,将裸机改造成功能更强,使用更方便的极其
所以操作系统作为最接近硬件的层次,需要实现对硬件机器的扩展.
通常我们把覆盖了软件的极其称为扩充机器,又称之虚拟机.

处理机是计算机系统中存储程序和数据,并按照程序规定的步骤执行指令的部件。程序是描述处理机完成某项任务的指令序列。指令则是处理机能直接解释、执行的信息单位。处理机包括中央处理器(cpu),主存储器,输入-输出接口。处理机加接外围设备就构成完整的计算机系统
中央处理器(CPU,Central Processing Unit)是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。
引起进程终止的事件:
- 正常结束
- 异常结束
- 外界干预
进程的终止过程:
如果系统发生了上述要求终止进程的某事件后,操作系统便调用进程终止原语,按下述过程去终止指定的进程👇
- 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程状态。
- 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真。用于指示该进程 被终止后应重新进行调度。
- 若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。
- 将被终止的进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。
- 将被终止进程(它的PCB)从所在队列(或链表)中移出,等待其它程序来搜集信息。
正在执行的进程,当发现上述的事件后,由于无法继续执行,于是进程便通过调用阻塞原语block把自己阻塞,课件,进程的阻塞是进程自身的一种主动行为.进入block过程后,由于此时该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由执行改为阻塞,并将PCB插入阻塞队列.如果系统中设置了因为不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列.最后,转调度程序进行重新调度,及那个处理机分配给另一就绪进程,并进行切换,然后,保留被阻塞进程的处理机状态(在PCB中),再按照新进程的PCB中给的处理机状态设置CPU环境
当被阻塞的进程所期待的事件出现时,如I/O完成或者其所期待的数据已经到达,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup(),将等待该事件的进程唤醒.唤醒原语执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中.
上面提到过很多次PCB,这里再着重讲解一下
为了使参与并发执行的每个程序,包含数据都能独立地运行,在操作系统中必须为之配置一个专门的数据结构,称为进程控制块(PCB,Process Control Block)。进程与PCB是一一对应的,用户进程不能修改。
进程控制块PCB的作用:
为了便于系统描述和管理进程的运行,在OS的核心为每个进程专门定义了一个数据结构——进程控制块PCB(Process Control Block)。PCB作为进程实体的一部分,记录了操作系统所需的,用于描述进程的当前情况以及管理进程运行的全部信息,是操作系统中最重要的记录型数据结构。PCB的作用是使一个在多道程序环境下不能独立运行的程序(含数据)成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。
进程控制块PCB中的信息:
在进程控制块中,主要包括以下几个方面的信息:
就到这里,希望能够帮助你,如果有哪里讲的不对或者不完善,请在评论区指正~谢谢