JVM 内存结构
描述
JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。而其他的数据依赖于每一个线程,在线程创建时创建,在线程退出时销毁
Java中的内存分配:
Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,就对数据进行了不同空间的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
一. 程序计数器
描述:程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
1)在线程创建时创建
2)当前线程所执行的字节码的行号指示器
3)执行本地方法时,PC的值为undefined
4)每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存
5)此内存区域是唯一一个在Java 虚拟机规范中没有规定任何OutOfMemoryError情况的区域
二. 虚拟机栈
描述:线程私有,它的生命周期与线程相同。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。
设置大小:-Xss2M
1)线程私有,生命周期和线程相同
2)栈由一系列帧组成(因此Java栈也叫做帧栈)
3)帧保存方法参数,方法的局部变量、操作数栈、常量池,指针
4)每一次方法调用创建一个帧,并压栈
三. 方法区
描述:方法区在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。
简单说方法区用来存储类型的元数据信息
设置大小:-XX:PermSize=10M -XX:MaxPermSize=10M
1)保存装载的类信息
2) 存储常量池
3) 存储static变量,方法信息(方法名,返回类型,参数列表,方法的修饰符)
4) 通常和永久区(Perm)关联在一起可以通过-XX:PermSize和-XX:MaxPermSize参数限制方法区的大小
5)方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的
6) 方法区也可被垃圾收集,当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集
四.常量池
描述:运行时常量池是方法区的一部分.Class文件中除了有类的版本,字段,方法,接口等描述信息外还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区运行时常量池中存放
五.堆(heap)内存
描述:堆是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存
设置大小:-Xms2g -Xmx2g -Xmn1g-Xss128k
-Xms2G 虚拟机内存最小2G
-Xms2G 虚拟机内存最大2G
-Xmn1G 年轻代内存1G
-Xss128 每个线程堆栈大小
1) Java 堆是被所有线程共享的
2) 存放对象实例,几乎所有对象的实例都在这里分配内存
3)堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。
4)堆的大小可以通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G
5) 默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列
6) 从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java 堆中还可以细分为:新生代和老年代
新生代:程序新创建的对象都是从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRation来调整Eden Space及SurvivorSpace的大小
老年代:用于存放经过多次新生代GC仍然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代,主要有两种情况:1、大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。2、大的数组对象,且数组中无引用外部对象。
老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。
六. 本地方法栈
描述:本地方法栈(Native MethodStacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现本地方法栈。
七. 直接内存
描述:直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。但是这部分内存也被频繁使用,而且也有可能导致OutOfMemoryError一场的出现
NIO(New Input/Output)类引入一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用Native函数库直接分贝堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,