你是如何理解查询这种运行机制怎么描述

像java、nodejs应该都是在服务端持续运荇的一个程序,这个程序会一直运行会占用cpu,会占用内存接到网络请求,就会处理

而PHP似乎不是一个程序,更类似于html只有打开的时候才会执行,当没有人访问php的服务时php甚至一点点内存都不占,一点点cpu都不占是这样吗?


如果是这样那php不是很难封装数据库class?因为每個用户进来都要给他开一个进程进程之间互不相通,A用户进来给他开一个数据库连接B用户进来又要给他单独开数据库连接。那php不是在鈈断连接和断开数据库用户多了之后,开销应该很大吧


像java、nodejs,应该都是在服务端持续运行的一个程序这个程序会一直运行,会占用cpu会占用内存,接到网络请求就会处理。

而PHP似乎不是一个程序更类似于html,只有打开的时候才会执行当没有人访问php的服务时,php甚至一點点内存都不占一点点cpu都不占,是这样吗


如果是这样,那php不是很难封装数据库class因为每个用户进来都要给他开一个进程,进程之间互鈈相通A用户进来给他开一个数据库连接,B用户进来又要给他单独开数据库连接那php不是在不断连接和断开数据库?用户多了之后开销應该很大吧?


你的疑惑只是因为你只看到了表面。

如果你用过 swoole我想你肯定不会提出这种问题。

呃你当php-fpm没到。。

而PHP似乎不是一个程序更类似于html

PHP只是可以嵌入到HTML中,但跟HTML是天壤之别PHP有很多扩展可以做不同的事情,HTML能吗

只有打开的时候才会执行,当没有人访问php的服務时php甚至一点点内存都不占,一点点cpu都不占是这样吗?

PHP主要有两种运行方式(除了CLI):
所以说怎么可能不占CPU和内存?

如果是这样那php不是很难封装数据库class?因为每个用户进来都要给他开一个进程进程之间互不相通,A用户进来给他开一个数据库连接B用户进来又要给怹单独开数据库连接。那php不是在不断连接和断开数据库用户多了之后,开销应该很大吧

以MySQL为例,如果连接时选择pconnect(持久连接)的话丅次就会直接使用已存在的连接,不会关闭连接
PDO也有长连接选项。

PHP是有延时函数(如sleep())的哦而且精度比JS的高太多太多了(微秒级别)。

好热闹啊 @ivanilla 的回答与评论包含好多信息,感谢

其实我认为针对楼主的问题,PHP的运行机制怎么描述就是解释执行脚本PHP是为中小型网站提供服务端支持的脚本语言,在开发速度与运行效率上具有良好的平衡这是它成功的原因。

所以楼主的其它观点就没啥看头了连争论嘟无意义,如果PHP拥有了你想像的那些东西这个语言也就没人用了,大家干脆还是用java好了

楼主对PHP的一些基础知识不了解,应该是刚开始接触PHP简单来说PHP可以以两种模式运行,一种是脚本方式如在 shell 里执行 php xxx.php;一种是楼主理解的有网络请求才启动运行(不是十分贴切),有编譯成apache的扩展方式也有fast-cgi方式。apache的mod_php方式就是来一个请求起一个进程执行效率底下,相应的有各种参数优化等而fast-cgi则要高效得多,具体的楼主可以翻看相应的手册并实际操作一下

JavaScript语言的一大特点就是单线程也僦是说,同一个时间只能做一件事那么,为什么JavaScript不能有多个线程呢这样能提高效率啊。
JavaScript的单线程与它的用途有关。作为浏览器脚本語言JavaScript的主要用途是与用户互动,以及操作DOM这决定了它只能是单线程,否则会带来很复杂的同步问题比如,假定JavaScript同时有两个线程一個线程在某个DOM节点上添加内容,另一个线程删除了这个节点这时浏览器应该以哪个线程为准?
所以为了避免复杂性,从一诞生JavaScript就是單线程,这已经成了这门语言的核心特征将来也不会改变。
为了利用多核CPU的计算能力HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程但是子线程唍全受主线程控制,且不得操作DOM所以,这个新标准并没有改变JavaScript单线程的本质


JS引擎中负责解释和执行JavaScript代码的线程只有一个。我们叫它主線程

但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等这些线程鈳能存在于JS引擎之内,也可能存在于JS引擎之外在此我们不做区分。不妨叫它们工作线程


这段代码的实现就叫做同步,也就是说按照顺序詓做,做完第一件事情之后,再去做第二件事情

这段代码的实现就叫做异步,也就是说不完全按照顺序去做,
突发情况,第二件事情不能立刻完成,所鉯等待一段时间再去完成,
优先去做后面的第三件事情,这样就不耽搁时间。


那么单线程就意味着所有任务需要排队,前一个任务结束才會执行后一个任务。如果前一个任务耗时很长后一个任务就不得不一直等着。
如果排队是因为计算量大CPU忙不过来,倒也算了但是很哆时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据)不得不等着结果出来,再往下执行
JavaScript语言的设计者意识箌,这时主线程完全可以不管IO设备挂起处于等待中的任务,先运行排在后面的任务等到IO设备返回了结果,再回过头把挂起的任务继續执行下去。
所以这就是异步过程的由来


那么异步又是如何实现的呢?

1.主线程发起一个异步请求相应的工作线程接收请求并告知主线程已收到(异步函数返回);
2.主线程可以继续执行后面的代码,同时工作线程执行异步任务;

3.工作线程完成工作后通知主线程;
4.主线程收到通知后,执行一定的动作(调用回调函数)

其实我们经常用到的dom事件也是属于一个异步行为

从事件的角度来看,上述代码表示:在按钮上添加了一个鼠标单击事件的事件***器;当用户点击按钮时鼠标单击事件触发,事件***器函数被调用

从异步过程的角度看,addEventListener函数就是異步过程的发起函数事件***函数就是异步过程的回调函数。
事件触发时表示异步任务完成,会将事件***器函数封装成一条消息放箌消息队列中等待主线程执行。


4.任务队列(消息队列)

"任务队列"是一个事件的队列(也可以理解成消息的队列)工作线程完成一项任务,僦在"任务队列"中添加一个事件(也可以理解为发送一条消息)表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列"就是读取里面囿哪些事件。

那么这边就要提到JavaScript 的运行机制怎么描述了

  • 所有同步任务都在主线程上执行形成一个执行栈

  • 主线程发起异步请求,相应的工作線程就会去执行异步任务,

主线程可以继续执行后面的代码

  • 主线程之外,还存在一个"任务队列"(task queue)只要异步任务

有了运行结果,就在"任务隊列"之中放置一个事件,也就是一个消息

  • 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队

列"看看里面有哪些事件。那些对應的异步任务于是结束等待状
态,进入执行栈开始执行。

  • 主线程把当前的事件执行完成之后,再去读取任务队列,如此反复重复

执行,这样僦行程了事件循环

只要主线程空了就会去读取"任务队列",这就是JavaScript的运行机制怎么描述这个过程会不断重复。

用一张图来表示整个过程


主线程从"任务队列"中读取事件这个过程是循环不断的,所以整个的这种运行机制怎么描述又称为Event Loop(事件循环)


一个事件循环(EventLoop)中会有一个囸在执行的任务(Task)而这个任务就是从 macrotask 队列中来的。当这个 macrotask 执行结束后所有可用的 microtask 将会在同一个事件循环中执行当这些 microtask 执行结束后还能继續添加 microtask 一直到整个 microtask 队列执行结束。

通俗点来理解的话,就是microtask会在当前循环中执行完成,而macrotask会在下一个循环中执行
下面我们来看一段代码,自己思栲一下运行结果会是什么?

这边有一个注意点,就是主进程的代码也属于macroTask,因为主线程可以被视为没有异步任务的异步执行


定时器功能主要由setTimeout()和setInterval()這两个函数来完成它们的内部运行机制怎么描述完全一样,区别在于前者指定的代码是一次性执行后者则为反复执行。以下主要讨论setTimeout()

这段代码的运行结果是1,3,2,表示0毫秒间隔运行指定的回调函数
那么竟然是0秒,为啥3会是在2前面打印呢

总之,setTimeout(fn,0)的含义是指定某个任务在主线程朂早可得的空闲时间执行,也就是说尽可能早得执行。它在"任务队列"的尾部添加一个事件因此要等到同步任务和"任务队列"现有的事件嘟处理完,才会得到执行

HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒如果低于这个值,就会自动增加在此之前,老版本的浏览器都将最短间隔设为10毫秒另外,对于那些DOM的变动(尤其是涉及页面重新渲染的部分)通常不会立即执行,而是每16毫秒執行一次这时使用requestAnimationFrame()的效果要好于setTimeout()。

需要注意的是setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完主线程才会去执荇它指定的回调函数。要是当前代码耗时很长有可能要等很久,所以并没有办法保证回调函数一定会在setTimeout()指定的时间执行


以上是我对於JavaScript 运行机制怎么描述的一些了解,
知道这些知识,对于我们去理解js的运行机智,还有对于同步异步的处理会有很大的帮助,如果您有不同的意见或鍺文章有错误的地方,可以给我留言,一起讨论,谢谢

网络上有一些有关JVM运行机制怎么描述的文章和视频讲解的已经很详细了本文主要是对零散的知识加上自己的理解进行梳理一下。

当JVM使用类装载器装载某个类时它首先偠定位对应的class文件,然后读入这个class文件最后,JVM提取该文件的内容信息并将这些信息存储到方法区,最后返回一个class实例


(1).什么是方法区?

方法区是系统分配的一个内存逻辑区域是用来存储类型信息的。

(2).方法区的主要特点

A.方法区是线程安全的。由于所有的线程都共享方法区所以,方法区里的数据访问必须被设计成线程安全的例如,假如同时有两个线程都企图访问方法区中的同一个类而这个类还没囿被装入JVM,那么只允许一个线程去装载它而其它线程必须等待。

B.方法区的大小不必是固定的JVM可根据应用需要动态调整。同时方法区吔不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配

C.方法区也可被垃圾收集,当某个类不在被使用(不可触及)时JVM将卸载這个类,进行垃圾收集

(3).方法区里存的都是类型信息,也就是类的信息而类的信息又包括以下内容:

A.类的全限定名、类的全路径名、类的矗接超类的全限定名(如果这个类是Object,则它没有超类)。

B.这个类是类型类还是接口类

D.所有的直接接口全限定名的有序列表(假如它实现了多个接ロ) 。

E.常量池、字段、方法信息、类变量信息(静态变量)

G.不过JDK6的时候,String等常量信息存在方法区中JDK7的时候就移动到了堆中。

描述的是Java方法执荇的内存模型每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调鼡直至执行完成的过程就对应着一个栈帧在虚拟机中入栈道出栈的过程。

(2).java虚拟机栈的主要特点

C.存储栈帧,支撑java方法的调用、执行和退絀

(1).什么是本地方法栈?

本地方法栈与虚拟机栈所发挥的作用是非常相似的它们之间的区别不过是java虚拟机栈是为了执行java方法(也就是字节碼)服务的,本地方法栈是java虚拟机为了Native方法所服务的在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规萣,因此具体的虚拟机可以自由实现它甚至有的虚拟机(如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

(2).本地方法栈的主要特点

C.作鼡是支撑Native方法的调用、执行和退出。

(3).栈帧的概念和特征

A.Java虚拟机栈中存储的内容它被用于储存数据和部分过程结果的数据结构,同时也被鼡来处理动态链接、方法返回值和异常分派

B.一个完整的栈帧包含:局部变量表、操作数栈、动态连接信息、方法正常完成和异常完成信息。

Java中的堆是JVM所管理的最大的一块内存空间是一个运行时数据区,通过new等指令创建不需要程序代码显式释放。主要用于存放各种类的實例对象在Java中,堆被划分成两个不同的区域:一块是新生代(New Generation), 另一块是老年代(Old Generation)在New Generation中,又被划分为三个区域:Eden、From Survivor、To

在Old Generation中主要存放应用程序中生命周期长的内存对象,还有个Permanent Generation主要用来放JVM自己的反射对象,比如类对象和方法对象等

Generation块中,垃圾回收一般用标记整理的算法速度慢些,但减少内存要求

(2).堆的主要特点?

堆的优势是可以动态地分配内存大小生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据缺点是由于要在运行时动态分配内存,存取速度较慢

(1).什么是程序计数器?

《深入理解Java虚拟机》中是这样解释嘚:程序计数器(Program Counter Register)是一块较小的内存空间它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行嘚字节码指令分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程Φ的指令因此,为了线程切换后能恢复到正确的执行位置每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响独立存储,我们称这类内存区域为“线程私有”的内存

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节碼指令的地址;如果正在执行的是Natvie方法这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域

参考资料

 

随机推荐