jvm(二):内存管理
jvm内存区域总体分为5大块:方法区,java堆,虚拟机栈,本地方法栈,程序计数器,按照线程来分的话又分为线程共享区和线程独占区
程序计数器:
a、程序计数器是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器
b、此区域是唯一一个在java虚拟机规范中没有任何outofmemoryerror情况的区域
c、如果线程执行的是java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果正在执行的是native方法(即本地方法栈服务的方法),这个计数器的值为undefined
本地方法栈:
a、本地方法栈为虚拟机执行native方法服务(虚拟机栈为虚拟机执行java方法服务)
虚拟机栈:
a、虚拟机栈描述的是java方法执行的动态内存模型
b、栈帧,每个方法执行都会创建一个栈帧,伴随着方法从创建到执行完成,用于存储局部变量表(存放编译期可知的各种基本数据类型,引用类型,returnaddress类型,局部变量表的内存空间在编译期间完成分配,当进入一个方法,这个方法需要在帧分配多少内存是固定的,在方法运行期间不会改变局部变量表的大小),操作数栈,动态链接,方法出口等。
c、可能出现StackOverflowError、OutOfMemory等异常
java堆:
a、存放对象实例
b、垃圾收集器管理的主要区域
c、堆被划分为两个不同的区域:新生代、老年代,新生代又被划分为三个区域:Eden、From Survivor、To Survivor
d、堆大小可通过参数-Xms、-Xmx来指定
e、会抛出OutOfMemory异常
方法区:
a、存储运行时常量池,已被虚拟机加载的类信息(类的版本,字段,方法,接口),常量(储存编译器生成的各种字面量和符号引用),静态变量、即时编译器编译后的代码等数据。
b、方法区中很少进行垃圾回收,但是会执行垃圾回收,回收效率比较低,如对常量池的回收,对象类型的卸载等。
c、会抛出异常OutOfMemoryError
注意:
如果Strng s1 = "abc" String s2 ="abc" s1==s2 输出为true
因为,定义s1的时候,在堆中创建对象,并记录在方法区的运行时常量池的StringTable表中,再定义s2的时候发现StringTable中已经记录了这个对象,就不在堆中创建新的对象了,s2会指向第一个abc,而不是图中的第二个
如果String s3 =new String("abc") ,则是s1==s3为false 直接在堆中开辟一块空间,而不再去考虑常量池的问题。如果,s1==s3.intern() 则返回为true,intern()方法会将s3的“abc”移动到运行时常量池中去(即产生一个运行时常量),但常量池中已经有“abc”所以相等。
注意,还有直接内存(主要是nio使用)的存在,其不受虚拟机内存的制约,但是受到物理内存的制约。