本文共 10022 字,大约阅读时间需要 33 分钟。
计算机的基本组成层次,每一层次面临的编程接口各有不同 比如第一层是硬件,如果要开发程序,面对的是硬件接口,硬件开放式提供所谓的编程工具,告诉我们这个硬件的编程的规格是什么,底层的规格通常是二进制的,即便是做了2次封装以后,就是所谓的汇编,在这个级别写的代码基本上是一对一的,你所写的每一条语句都是在硬件上执行的一个操作,因为cpu真正所执行的操作就是一个个的指令组成的,你写的每个语句就是一个指令,基于这个语句执行一条指令,你写循环,循环几次,就执行几次,没有浪费,但是这种方式对于程序员来讲太痛苦,这个语言离机器非常近(低级语言),但是离人比较远 低级语言并不是说性能差,只是说离机器较近 离用户较近的语言,叫做高级语言,高级并不意味着性能好,也不是有先进技术,而是说接近于人类的自然语言,写起程序来,人比较舒服
硬件向上一层,为了避免硬件编程接口的,各种硬件的不同,使用的程序极难移植,一个硬件在一个时候只能运行一个程序 为了能突破这种限制,后来才有操作系统 这种操作系统,多数现代的操作系统都是多任务多用户的,操作系统把底层有限的硬件资源,给切割出很多份,能供多个进程来运行,所以从这个角度来讲,操作系统内核是硬件平台接口的抽象层,所以可以理解为是硬件设备上的虚拟机,把一台计算机虚拟了很多台(计算机的5大组件在某一个时刻只能跑一个程序) 为什么有了操作系统可以跑多个进程,硬件被虚拟了,cpu被切割成了时间片,内存被切割成了存储空间的一段一段,而后再拼凑起来,按部分,按量,按需供给给所需要用的程序,并把他们放置在隔离的空间当中,进程和进程彼此之间是没有任何感知的,每个进程也认为世界上只运行了自己和内核 所以可以想象成内核把计算机底层的硬件资源给分配成一个一个的沙箱,sandbox,与外部是隔绝的,除了内核之外 因此内核把底层的cpu,切割成时间轮替以后的时间片以后,每一片按需分派给每一个沙箱,所以每个沙箱所能获得的cpu只是时间流逝的提供的计算能力中的一部分 内存也是一样的,内存是被切割成很多称为叶匡的存储空间,一个只有4k的大小,这个4k的叶匡被按需分配给进程,而每一个进程的程序员写程序的时候,它是需要连续操纵内存的,它并不知道用的是哪个叶匡,不同场景分配的叶匡也是不一样的,所以为了减少程序员的压力,所以现在用的都是虚拟内存,也叫线性内存 每一个进程在运行时,以32位为例,最大的虚拟内存空间是4g,从0开始编号的,到1g是内核的,其他都是自己的, 这个1个G当中,有些是其他的进程,需要做映射 内核中就不得不为每一个进程建立追踪表,任务结构的追踪表,这个表里记录的每一个进程,它的真正的线性内存空间和物理内存空间的映射关系,所以每个进程访问自己的空间,用的数据时,它自己看到的这个线性地址,但这不是真实的,需要先转换成物理地址才能找到数据 这是在这个层级上实现,所以内核提供计算机的虚拟机机头,才使得一份一份资源能够供多个程序使用,从这个角度来讲,已经算是虚拟机了 有了操作系统以后,编程接口所写的程序不是直接运行在硬件上的,而是运行在操作系统之上的,所以受控的机制,所对接的人不再是硬件而是操作系统。 而操作系统把底层硬件给隐藏起来,为了能够组织成类似的虚拟形式,那需要把自己内部的各种功能给隐藏起来,提供另外一个接口调用,所以程序员写程序,就得基于系统调用去写了, 而系统调用一样非常底层,基本上,虽然算不上一对一,但至少也是极其接近底层硬件所提供的功能,功能收束起来,用很少量的调用接口,提供给程序员不用记那么多的库,接口,就能够简洁地写入程序,但是这样离我们最终用户太远, 所以后来不会让用户直接从头去造轮子,再抹上一层‘’库‘’ 叫做库接口,库接口并没有隐藏底层的system call,程序员写程序时,可以直接系统调用,也可以到库调用,两种方式都可以,库把大多数程序中所需要的基本功能,都放在库一层了,用库来编程,他们所共享连接的编程, 程序员的指令是不会变的,所有变的就是数据,所以分为只读,和可写两部分 可操作数据,指令是不变的 库当中的都是指令,要加工的数据一般是程序从外部文件中加载过来的,可以借助于库来完成某些操作 所以这是库接口,有了库接口以后,这个代码又可以只读,又可以放在内存共享,每一个进程虽然都有自己的地址和空间,但是有些内容并没有直接放在地址空间,是供多个程序大家共享的,因此可以极大的集约, 这里提供的编程接口一般是系统级别的编程接口,离我们的底层硬件依旧非常近,而现代几乎除了操作系统之外,大多数程序,他们都不会期望运行在硬件之上,所以几乎所有程序员所面临的编程接口都应该是系统级接口,这个系统级接口通常和编程语言C,C++ 有很多手机厂商的程序员,需要个手机各种硬件写驱动,比如要给空调的遥控嵌入式芯片开发一个运用程序,这个空调的芯片只运行一个程序,就是供我们开启以后控制空调运行的,所以这里面对的就是原生的芯片接口 但是这里有一个坏处,操作系统的接口叫系统级API,各种操作系统提供的编程接口是不尽相同的,在A机器开发的程序,到了B机器上没有这个接口,就无法使用了 所以标准化组织,后来就弄了一个posix API(posix可移植操作系统),windows,linux都有一个函数,那么这个程序都可以使用 程序员写出来都是文本文件,和cpu上的指令集是不对应的,真正的程序运行必须是调用cpu支撑的每一条命令通常是二进制格式来运行,cpu在设计上就支持一些指令可以直接进行操作,所谓的写程序就是调用这些指令来运行的,但你写出来的是文本文件,文本文件不可能是cpu上能执行的指令,我们要转换成cpu可识别的文件格式, (解释执行,执行一句翻译一句) 但是对第二种方式来讲,通篇翻译,真正执行起来哪个比较好,当然是编译,事先都翻译好,一目十行的看都可以,而传译,是看一句翻译一句 编译好以后,它的运行时要调用内核所提供的共享库等内容的,而不同的内核所提供给程序运行的调用接口时不一样的,称为ABI(windows运行格式exe,msi,linux运行格式,elf),所以编译前兼容,编译后又不兼容,因为ABI 不兼容,所以编译后去运行的时候,格式还是不兼容的 所以这样就导致,现在有个程序必须要编译好,分发给全球用户,但是很大一部分人会无法运行,因为大家系统接口并不一样,比如有用 mac os,Ubuntu,windows 所以这样发现,程序分发起来非常困难,要想做到一个程序快速完成分发,任何操作系统都能运行,层次不相间,就需要再加一个中间层 在操作系统之上在抹上一层,让每个操作系统都能有这么一层,而后这个层次所提供的是完整的接口,,包括开发,写语言,编译,但是不必要转换成二进制格式的,由自己翻译成底层应用的格式就可以 由此我们写的程序,不是操作系统的接口,也不是硬件接口,也不是库接口,而是整个层次所提供的,另外一级接口,所以要提供一个新的编程语言接口,用户就利用它的接口写程序,写完程序,运行的时候,需要由它来同声传译给底层内核和硬件去执行,一句传译/转换一句的执行,这样性能就会变得很差,但是有一个好处在于方便移植,任何操作系统只要有这么一层,它负责的对应转换成底层语言,比如底层是windows,接受的内容是一样的,只不过转换成windows的语言,所以这个应用程序是一个层次精通多门语言的, 这种称谓应用编程接口,所以可以使我们代码一次编写到处运行,wirte once,run anywhere 这种编程语言有很多种,java,ruby,perl 这里有一个问题,代码离我们的硬件非常远了,中间可能会产生很多废话,因为在这个语言本身,可能只需要写一条指令,而转换成底层硬件都已经是几十条指令了 但是好处是离我们的自然语言越来越近了,解脱了程序员开发程序时的压力,但增加了程序运行时的压力,这在早些年是不可想象的,但现在cpu,18个月发生一代,人的脑力几十万年才进化到今天的程度的,短短几十年cpu执行能力已经翻了无数倍了,因此浪费一点计算机的时间来节约自己用户的时间,显而易见收益大于损耗的, 所以现在为什么编程语言用高级语言越来越多,而早些时候都是底层语言,(计算机进入23世纪了,进化速度非常快) 这种语言性能差就差了,但是我们要编辑一个简单的应用,如果用python开发一个内部运维系统,用户是内部运维人员,并发很少,对系统没有很高要求,但如果开发应用程序需要支撑线上多人来访问应用的,那就另当别论 了,所以会发现,这些应用程序,普通的没问题 但是要开发一个高性能高并发的程序来讲,高级语言确实先天不足,因此人们已经习惯了用简单方式写代码,而又先天不足不能去写高性能程序,这种困境如何解决,所以你会发现,写高并发高性能的应用时,一般又得回归下一层的系统级开发, 但是golang出现了,拥有应用级编程的代码的简介,同时又拥有所谓的系统级编程代码的性能,因为golang的作者 三个,linux之父之一 汤姆森是牵头人,另外两个人也很牛叉, 在google的推广下,golang显现出来足够的生命力,07年出现,到现在,越来越多的编程语言都来用go来实现 ,尤其是一些底层后端应用的,比如doocker,etcd(高可用的键值存储系统),go开发的 golang适合取代,python,java等一众语言在编写高性能应用方面确实的性能方面的表现,所以是用来取代这些应用的, golang是编译性的语言,好处在于将来要部署一个python,要依赖很多第三方库的时候会发现,不得不手动解决依赖关系, 对大多数用户来讲,这是及其麻烦的事情, 有了golang以后,这是一种编译性语言,就像c程序一样,编译好了就是自动分发的,可以静态编译也可以动态编译, 这就是go语言最近这么火的原因,是用来取代C,C++,但是主要目标是为了javapython设计的 而真正用来取代C/C++,是rust 国内有个著名的开源数据库TiDB,国内创业公司构建的,tidb目前已在全球获得了极大的青睐,刚拿了1500w美元的风头,目前正进入快速发展期 php,python,java各自都有特性和优势,所以存在即合理,这么多年以来,java作为老大的地位从未被撼动过,这种需求趋势还有上升的态势,因为越来越多的php程序员走向java了 但是也不乐观,因为go语言在各种后端高性能语言当中,不断蚕食java已经有的份额ja va编程语言是一个很老的语言,最初的设计目的也是为了解决c/c++这种编程时代,程序不便移植问题的, 而那时候美国正兴起了电视机的机顶盒(公司各自都能生产,每个规格都不一样,程序员写程序的时候就会发现,A机顶盒适用,B机顶盒就不适用,),所以就决定开发一个编程语言,一次编译,到处运行 上世纪90年代,硬件性能还跟不上,内存还是几M 到2000以后,才有64M内存,还是大内存,所以要用java来运行程序,无疑是失败的,所以当初设计出来后,认为是失败的,因为没有人用,但是无形插柳,柳成荫,因为刚好90年代初期有一种应用诞生了,www万维网 web应用,实得我们的网站,构建以后,呈现给使用者,(静态内容),但是就需要有动态内容(需要代码,需要程序,这段代码早期的时候不是在服务端运行的,客户端请求,代码会原封不动的过去,在客户端解析执行,所以还是静态资源) 但是客户端不尽相同,不可能到处运行 那时候只需要在计算机安装这个虚拟机运行程序,每个操作系统只要有个层的软件装上,这个代码就能在这个软件上运行了,所以只要访问互联网的时候,想呈现出这个动态效果来,就只要给每个计算机装上环境就可以了。 java有一个类库,既是一个编程接口,也是一个完整的语言。(有一个类库叫applet,小程序,使用applet开发的小程序,可以直接放在服务器端的网站主目录下,客户端取过来就可以执行,在桌面上显示动态效果了,在那个时代已经非常炫了,因为其他页面还都是静态的) 一个产品一旦找到了自己的市场价值,那么很显然就能进入发展的快车道了,所以java就一路发展下来, 但是代码让客户端运行还是有一定的风险,如果有人写了恶意代码, 现在是让服务器端运行,客户端请求,服务器收到识别这个资源需要运行的哪些资源,(要运行代码,需要安装一个环境,比如PHP,因此要想让php的解释器运行起来,这个解释器和httpd,之间没有关系,httpd要想运行代码需要启动一个php的解释器,那就要解释器允许另外一个进程触发启动,并且还要接收对方传递的数据,理解意图是什么,中间就需要一个协议,就叫CGI,通用网关接口,) 有了通用网关接口,使得如果我们文本服务程序能够支持通过 通用网关接口CGI协议,调后端的应用,那这个应用本身在提供能够被别人调用的CGI接口,这个应用程序就可以让用户借这个编程语言去开发动态网站了,后来各种编程语言都纷纷添加了这个CGI的支持,包括C和C#都支持,所以动态网站可以在服务端运行了,只不过这么一来,要求服务器收到请求以后,不能直接响应给客户端,而是要自己基于这种协议调用接口,去掉用一个应用程序,并把用户请求的这个页面资源内容人,让它能加载到解释器,运行结果再通过 CGI协议返回给前端的web服务进程 java也要运势而变,applet(客户端运行的小程序)servlet(服务端运行的小程序) 基于CGI调java运行的接口(jvm) 运行结果给web进程,给客户端
之后就进入servlet时代,进入servlet时代,也会有个问题,网站为了能展示标题,需要基于html语言的元素来组织生成精美的标签,如果网站是通过应用程序生成的,这些标签该怎么办,需要用程序生成 但是这个程序员开发及其痛苦,又要知道怎么去处理数据,又要怎么想去实现网站如何布局,既要走前端,又要走后端 对于java语言来讲,想要实现这种效果,后来研发了一个应用,能够使自己的java代码嵌入到html中去,而不是自己输出这些标签,叫jsp(java server page java服务器端页面) jsp有一个对应程序叫jasper,当你写了一个嵌入式的代码以后,jasper会翻译成servlet,还是有程序输出的,但是我们程序员不需要自动去写完,只需要文本放到那,jasper能把它转换成“echo <h1"这样的语句 这样就可以把前后端开发分离出来,最终整合起来以后,就那jasper进行转换,转换以后依然是servlet,事实上并没有改变,只不过多了一个步骤,程序员写程序变的简单了,可以前后端分离了,而jasper需要把分离的前后端转换成统一代码,成为servlet,然后以servlet再运行,servlet还是以cgi的方式运行的,一个应用 这就是java当中的一个类库,(java纯面向对象的编程语言,所以内部的各组件都得成为类,而后发展为对象,对象彼此之间打架或操作完成程序运行) 目前编程语言有两大范式,对象式,过程式,对程序来讲就是把A的问题,A的一种模型转换成B的模型,所以需要对A,B模型都很熟悉的时候,才能灵活去写程序,转换方式有两种,过程式,对象式 过程式编程指的是以指令为中心,数据服务于指令,需要什么样的数据结构,就组织成什么样的数据结构 被组织成高效解决问题的方法叫算法, 而算法通常需要让我们把数据组织起来能符合自己高效运行的需要,数据结构对象式编程指的是 以数据为中心,指令是服务于数据的 人算一个类,给它的每一个属性赋一个值,变的具体起来就叫实例化,对象化 数据就是类,并基于对类做实例化来完成的,(对象) 对每一个对象来讲,都有固定操作方式 每一种对应 的对象,我们可以指明只能基于哪种接口去调用,使用方法有哪些 代码指令会生成方法(函数),一个类定义了哪些方法,就只能调用它的哪些方法,那这个方法是可以操纵当前类所实例化的当前对象, 对于对象式编程来讲封装多态继承,封装 java是纯对象是编程的语言,只要用java编程,都得首先设计类,设计类中的方法,把类实例化对象,一个对象支持哪些方法由类来固定,还有一些高级的方式,抽象类之类的
python,既可以过程式编程也可以对象式编程,取决于你自己的编程需要,构建大型应用,一般对象式编程代码更加清晰,维护更容易
java是sun公司研发的,oracle收购sun为了对付google,java其实是开源的,Android用了java代码,但有一些库没有开源,在Android中调用了此库,oracle要求每一次这个数据的分发都要付一笔费用,这个费用算下来有100多亿美元 但是每个法官花了一年时间精通java代码,判断只是调用,不涉及侵权,oracle败诉 java实际是个完整的技术体系,为了能运行java代码,还需要提供java编程语言 jdk包含了很多组件,jvm,类库API,javac等 Java: Sun, Green Project, Oak, James Gosling; 绿色工程 1995:Java 1.0, 口号 : Write once, Run Anywhere; 1996:JDK(Java Development Kit), 包含类库(API)、 开发工具(javac java编译器,编译结果不是cpu的指令,而是jvm的指令,叫字节码)、 JVM(SUN Classic VM )早期sun公司组件研发的java虚拟机 ,后来sun公司收购了另一家公司,hotspot(专门研发了一个java虚拟机,认为hotspot还不错,所以现在内建的jvm商标都是hotspot) JDK 1.0, Applet(客户端应用), AWT 1997:JDK 1.1 1998: JDK 1.2(jdk本身代表整个java技术体系) 后来分为3个方向,1.2称为J2 Sun分拆Java技术为三个方向: J2SE:Standard Edition 标准版 J2EE:Enterprise Edition 企业版 J2ME:Mobile Edition (几乎没人用) 代表性技术:EJB,java plugin, Swing, JIT(Just In Time,即时编译) 到2000年 2000:JDK 1.3 HotSpot VM 2002:JDK 1.4 2006:Sun开源了Java技术,GPL,建立一个称为OpenJDK组织;(开源jdk) Java 2 SE, Java 2 EE, Java 2 ME 2011:JDK 1.7 2014:JDK 1.8 2016:JDK 1.9 jdk代表javese (java标准版的技术) 企业级就是在标准版上加了一些企业用到的类库EJB,JSP,都属于javaee的功能 jdk只包含了java基础开发包组 内部jdk都有一个代称jdk开发环境工具箱包含了jvm,类库 JRE java运行时环境 jvm如果要运行的代码需要类,但自己没有就需要去jre去找 jre就是类库+jvm组成 所以开发软件需要装jdk 写了代码之后可以用javac编译,编译以后就可以在jvm里运行了
真正运行jvm的时候,是不会有个程序叫jvm,而是通过java运行环境,比如一个代码,要用.java这样的命令把对应的文件装入jvm,并把对应的程序文件所依赖的库也装进jvm,来运行的 就像之前运行的c程序一样,所依赖的共享库必须现在内存中运行, 所以真正运行的是靠java运行的,所以你看不到运行的每一个java程序,每个进程都叫java,是用java来加载另外的文件和它的程序环境运行一个进程的转载地址:http://rbkgn.baihongyu.com/