java 内存, 类加载g
1. java 内存区域
方法区 | 虚拟机栈 | 本地方法栈 |
堆 | 程序计数器 |
其中 : 方法区 和 堆 是所有线程共享的 , 其他是线程隔离的
1. 程序计数器 : 可以看做是当前线程所执行的字节码的行号指示器。 字节码解释器在工作时通过改变这个计数器来选取下一条需要执行的字节码指令。
由于java 的多线程是通过线程轮流切换来分配处理器执行时间的方式来实现的,所以在任何一个时刻,一个处理器只会执行一个线程中的指令,
所以,为了在线程切换后能够找到正确的字节码执行位置,所以每个线程都有一个独立的程序计数器。所有程序计数器是线程私有的。。
该内存是唯一一个在java 虚拟机规范中没有规定OOM 异常的区域。。
2. 虚拟机栈:是线程私有的,生命周期和线程相同。 虚拟机栈描述的是java 方法执行的内存模型 : 每个方法在执行时都会创建一个栈帧,用于存储
局部变量表、操作数栈、动态链接、方法出口等信息。每个方法的调用过程就对应一个栈帧在虚拟机栈中从入栈到出栈的过程。
局部变量表: 存放编译器可知的各种基本类型(boolean,byte ,char ,short ,int ,long ,float ,double)、对象引用、returnAddress(指向一条字节码命令的地址)。
其中long和double占用两个局部变量空间,其他占一个。 局部变量表所需内存空间在编译期期间完成分配。
可能产生 stackoverflow(栈深度太大) 和 OOM
虚拟机栈 | 一个栈帧 | 局部变量表(基本类型,对象引用,returnAddress) |
操作数栈 | ||
动态链接 | ||
方法出口 | ||
一个栈帧 |
3. 本地方法栈: 与虚拟机栈的区别是 ,虚拟机栈是为执行java 方法服务的,而本地方法栈则是为使用native 方法服务。
4. 堆 : 存放所有的对象实例和数组, 可以通过xms 和 xmx 扩展大小。所有线程共享
5. 方法区: 线程共享。 用于存储已被虚拟机加载的类信息,类常量,类静态变量 (注意和栈的不同,方法区是相对类的),即时编译器编译后的代码。
类信息:类的版本,字段,方法,接口等描述信息外,还有一项信息常量池。
常量池:用于存放编译期(注意是编译期,比如 String s = "a"+k(k=“bc”或者k=new String("bc")) 和 String s1= "abc" 是不相等的)生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区的运行时常量池。
问题 : 栈中局部变量表 和 方法区的运行时常量池到底怎么区分? 参考 https://blog.csdn.net/xing930408/article/details/74090641
局部变量表(基本类型,对象引用,returnAddress) |
用于存放编译器生成的各种字面量和符号引用 |
问题的关键是怎么理解基本类型和各种字面量
带final的基础类型和String类型并且用常量表达式初始化的才算字面量,其他的都不是。
比如 int a=1存放在栈中,因为这个不是常量