java - JVM


SUN官方站点介绍JVM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#G1Options

JVM内存结构

Java 虚拟机在执行 Java 程序的过程中会把他所管理的内存划分为若干个不同的数据区域。分别是:方法区、堆区、虚拟机栈、本地方法栈、程序计数器。
其中方法区和堆区是线程共享的;
虚拟机栈、本地方法栈和程序计数器是线程隔离的。
除了程序计数器都会产生内存溢出。
在这里插入图片描述

方法区

用于存放已被虚拟机加载的类型信息,常量,静态变量、即时编译后的代码等信息。

方法区是线程间共享的,当两个线程同时需要加载一个类时,只有一个类会请求ClassLoader加载,另一个线程会等待。

静态代码块也在方法区,它在类加载期间运行。
思考:为什么全局变量放在静态代码块中?
因为在整个程序执行过程中,类只加载一次。那么静态代码块也只执行一次。

堆区

堆是Java 虚拟机所管理的内存中最大的一块,它是被所有线程共享的区域,是在虚拟机启动时创建的

堆里面存放对象和数组实例

我们平常所说的垃圾回收,主要回收的就是堆区(还可能有方法区)。如果垃圾收集算法采用按代收集(目前大都是这样),这部分还可以细分为新生代和老年代(默认2:1,可修改)。

其中新生代又可划分为Eden区和2个Survivor区,即From Survivor与To Survivor(默认8:1:1,可修改),主要是为了垃圾回收。所有的线程共享Java堆,在这里还可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAF)。

堆内存结构如下图结构:
在这里插入图片描述
堆只要求逻辑上是连续的,在物理空间上可以不连续。

虚拟机栈

线程 —> java虚拟机栈;
方法 —>栈帧(栈帧存储在java虚拟机栈中)

虚拟机栈是线程私有的,生命周期与线程相同。创建线程的时候就会为这个线程创建一个虚拟机栈。

虚拟机栈表示Java方法执行的内存模型,每调用一个方法,就会生成一个栈帧(Stack Frame)用于存储方法的局部变量表、操作数栈、方法出口等信息,当这个方法执行完后,就会弹出相应的栈帧。

栈帧分为以下几个区域:局部变量表、操作数栈、动态连接、方法出口等。
平时我们所说的变量存在栈中,这句话说的不太严谨,应该说局部变量存放在java虚拟机栈的局部变量表中。java的八种基本类型的局部变量的值存放在虚拟机栈的局部变量表中,如果是引用型的变量,则只存储对象的引用地址。

当用户请求web服务器,每个请求开启一个线程负责用户的响应计算(每个线程分配一个虚拟机栈空间),如果并发量大时,可能会抛出OutOfMemoneyError异常,可以适当的把每个虚拟机栈的大小适当调小一点,减少内存的使用量来提高系统的并发量。当栈空间调小以后,又会引发方法调用深度的的问题。因为,每个方法都会生成一个栈帧,如果方法调用深度很深就意味着栈里面存放大量的栈帧,可能会抛出StackOverFlowError异常。

本地方法栈

本地方法栈与虚拟机栈类似,只是是执行本地方法时使用的。

程序计数器

类似于PC寄存器,是一块较小的内存区域,通过程序计算器中的值寻找要执行的指令的字节码,由于多线程间切换时要恢复每一个线程的当前执行位置,所有每个线程都有自己的程序计数器。这一区域不会由OutOfMemoryError。当执行java方法时,这里存储的执行的指令的地址,如果执行的是本地方法,这里的值是Undefined。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章