Java 虚拟机学习 不断积累

来源:互联网 发布:mac装win10有什么坏处 编辑:程序博客网 时间:2024/05/30 23:29

·Java虚拟机运行期的几个概念 

Java虚拟机运行期的几个概念,方法区:存储类,静态变量,其他一些运行时参数;堆:存对象和数组;方法区和堆是共享的。程序计数器:记录代码运行到那一行;虚拟机栈和本地方法栈分别服务于Java虚拟机的方法调用和本地系统的Native方法调用。
后面三个都是线程私有的。 

·Java 虚拟机内存分配方式分为指针碰撞和空闲列表

Java 虚拟机内存分配方式分为指针碰撞和空闲列表,前者在JVM内存区域中指针一边是已分配内存,另一边是未分配内存,这种情况需要内存压缩。空闲列表则需要维护一套内存空闲和使用表。

·JVM之Java类实例化的过程 

JVM之Java类实例化的过程,这里不讨论这个类是数组和class类的情况。首先JVM需要在方法区的常量池查找这个类对应的类符号引用,并且检查这个符号代表的类是否被加载,解析和初始化过,如果没有找到就需要加载这个类到方法区。第二,JVM在堆中根据类的相关信息为这个要创建的对象分配一定大小的内存(指针碰撞或者空闲列表策略),实际分配的时候采取CAS或者TLAB策略。第三,将分配的内存内容初始化为零值(不包括对象头;LTAB策略可以在分配内存的同时完成这个操作)。第四是为对象设置Object Header,,虚拟机实例化对象的工作就完成了,但是从语言层面来说,还需要执行init()方法,把对象按照程序员的意愿初始化。

·JVM之对象的内存布局

HotSpot虚拟机中,对象在内存中存储布局分为:对象头(Header)、实例数据(Instance Data)和对齐填充。其中对象头分为两部分,第一部分是定长的,在32位虚拟机中为32bit,在64位虚拟机中为64位,用于记录对象运行时的不同状态;第二部分是指向它的类元数据的指针,通过该类型指针可确定其属于哪个类,此外对于数组而言,需要再加第三部分来记录数组长度,强调下普通对象通过元数据信息即可确定大小。实例数据用以存储对象真正的信息,遵循一定的分配策略。至此对于对象头部和实例数据占用的空间合未必是8字节的整数倍,而HotSpot VM要求对象的起始地址必须是8字节的整数倍,即对象大小必须是8字节的整数倍,而对象大小是根据类元数据得到的,当这个大小不是8字节的整数倍就需对齐填充,填充这部分即对齐填充,当不需填充时就不存在了。所以对齐填充部分不是必然存在的。

·JVM之Java栈(虚拟机栈)调用堆中的对象的方式

 Java虚拟机栈(简称Java栈)描述的是Java方法执行的内存模型(内含局部变量表,也叫本地变量表),本地方法栈为调用Native方法服务,都是方法级别的。Java堆存储对象实例和数组。方法区存储类信息,常量,静态变量,即时编译器编译后的代码,运行时常量池存在于方法区。Java虚拟机栈访问对象的方式有两种,句柄和直接指针,句柄存储对象实例数据的指针和对象类数据的指针,直接指针存储的就是对象地址和对象类数据的指针,前者好处是reference指向确定,坏处是需要多一次操作,频繁操作会影响效率。Sun HotSpot是具体指针。



·JVM之内存溢出-堆、虚拟机栈和本地方法栈(Java栈)、方法区

Java虚拟机中,除了程序计数器外,其他内寸区域都有可能发生内存溢出,OutOfMemoryError(OOM)。VM Args:-Xms20m -XmX20m设置Java堆大小固定为 20M。-XX:+HeapDumpOnOutOfMemoryError在堆内存溢出时会Dump出当前内存转储快照,可以用Eclipse Memory Analyzer打开。-Xoss设置本地方法栈大小,-Xss设置Java栈大小。HotSpot不区分虚拟机栈和本地方法栈,故-Xoss参数无效。Java栈可能出现OOM和StackOverflowError(递归调用)。XX:PermSize和-XX:MaxPermSize限制方法区大小。在内存空间一定的前提下,线程数越多越可能导致栈内存溢出而不是StackOverflowError。原因是栈帧每分配一个就消耗一定的内存空间,线程越多分配越多,发生内存溢出的概率越大,单线程由于在已分配好的栈帧操作,出现StackOvetflowError的概率更大。栈帧大小是不固定的,默认配置下大小下,对于包括递归在内的正常方法调用,深度达到1000~2000是正常的。

·String.intern()和字符串常量池

 String.intern()是一个Native方法,其作用为:如果方法区的运行时常量池中的字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象。否则将该String对象添加到常量池,并返回此String对象的引用。可以通过-XX:PermSize和-XX:MaxPermSize限制方法区大小。从而限制运行时常量池大小。