JVM运行时数据区域之程序计数器
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙里面的人想进去,墙外面的人却想进去-----------《深刻了解java虚拟机》
在用C编程的时候,咱们malloc一块空间总是须要手动进行free,不然就会造成内存泄露即应用过的内存没被开释,造成内存不够用了;而在Java中,垃圾回收器会主动帮咱们回收在后盾回收那些不再“应用”的内存,所以在Java编程中不容易呈现内存泄露和溢出的问题。然而一旦呈现例如java.lang.OutOfMemoryError:Java heap space之类的溢出,如果你不理解JVM运行时数据区域,那么你就可能又要默默的关上浏览器,面向百度开始编程了,所以说学习JVM还是十分重要滴!
tip:接下来会带大家一步一步学习JVM的相干内容,这一篇先带大家理解一下程序计数器,比拟好了解,全当热身。
运行时数据区域
先概览一下,不同的JDK因为优化的问题所以内存区域会有不同,然而整体的一个的构造还不变的。
Java虚拟机在执行Java程序的时候会把它治理的内存区域划分为若干个不同的数据区域,这些区域各有各有的用处,创立以及销毁工夫。有些内存区域由所有线程共享,有些则线程公有;有些内存区域随着用户线程的启动和完结而建设和销毁。
加点料
在java线程中有俩类线程,用户线程和守护线程;用户线程就是在咱们创立线程时的默认的一类线程,它容许在前台,例如咱们执行main办法的时候,JVM会启动一个main线程,这个main线程就是用户线程;而守护线程就是运行在后盾的线程(默默守护,我哭辽),它服务于用户线程,例如GC时的GC内存回收线程。 JVM与用户线程共存亡,只有有用户线程JVM就不会进行执行,当只剩下守护线程时,JVM才会进行执行
热身之程序计数器
在介绍java的计数器前,我先来讲一下CPU中的程序计数器,这俩个东东给大家一起介绍感觉可有助于了解
CPU中的程序计数器(PC)
CPU中的PC是一个大小为一个字的存储设备(寄存器),在任何时候,PC中存储的都是内存地址(是不是有点像指针?),而CPU就依据PC中的内存地址,到相应的内存取出指令而后执行并且在更新PC的值。在计算机通电后这个过程会始终一直的重复进行。计算机的外围也在于此。这个过程我会在字节码执行引擎那局部深刻去介绍一下。
JAVA运行时数据区域程序计数器
在CPU中PC是一个物理设施,而java中PC则是一个一块比拟小的内存空间,它是以后线程字节码执行的行号指示器。在java的概念模型中,字节码解释器就是通过扭转这个计数器中的值来选取下一条执行的字节码指令的,它的程序控制流的指示器,分支,线程复原等性能都依赖于这个计数器。
咱们晓得多线程的实现是多个线程轮流占用CPU而实现的,而在线程切换的时候就须要保留以后线程的执行状态,这样在这个线程从新占用CPU的时候能力复原到之前的状态,而在JVM状态的保留是依赖于PC实现的,所以PC是线程所公有的内存区域,这个区域也是java运行时数据区域惟一不会产生OOM的区域
加点料一:
先给大家看一下字节码的样子,前面在具体介绍
源程序
public class Main { public static void main(String[] args) throws IOException { int a=1; int b=2; System.out.println(a+b); } }
javac编译后的局部字节码
{public static void main(java.lang.String[]) throws java.io.IOException; descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=3, args_size=1 //栈深度最大为3,3个变量槽 0: iconst_1 //常量1压入栈 1: istore_1 //栈顶元素出栈存入变量槽1 2: iconst_2 //常量2压入栈 3: istore_2 //栈顶元素出栈存入变量槽2 4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; //调用静态方法main 7: iload_1 //将变量槽1中值压入栈 8: iload_2 //将变量槽2中值压入栈 9: iadd //从栈顶弹出俩个元素相加并且压入栈 10: invokevirtual #3 // Method java/io/PrintStream.println:(I)V //调用虚办法 13: return //返回 LineNumberTable: line 18: 0 line 19: 2 line 20: 4 line 21: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 args [Ljava/lang/String; 2 12 1 a I 4 10 2 b I Exceptions: throws java.io.IOException }
加点料二:
操作系统治理多过程:每fork()创立一个过程,OS会为这个过程创立一个PCB(Process Control Block)来记录这个过程的信息例如PID等,当产生过程切换的时候,OS会在PCB保留过程执行的以后的信息,例如内存,寄存器应用的状况等,在复原过程的时候,再依据PCB复原状态
//代码,ax,bx,cs就是寄存器 //pCur以后过程PCB,pNew下一个执行线程的PCB switch_to(pCur,pNew){ //以后过程执行信息保留到PCB中 pCur.ax=CPU.ax; pCur.bx=CPU.bx; pCur.cs=CPU.cs; ..... //复原过程执行信息 CPU.ax=pNew.ax; CPU.bx=pNew.bx; ..... }
程序计数器的内容感觉有点少,为了不让大家感到干燥,所以加了点料 ,peace;
最初
我是不想当码农的小白,平时会写写一些技术博客,举荐优良的程序员博主给大家还有本人遇到的优良的java学习资源,心愿和大家一起提高,独特成长。
以上内容如有谬误,还望指出,感激
公众号点击交换,增加我的微信,一起交换编程呗!
公众号: 小白不想当码农