JVM笔记整理

这只是一篇自己看JVM原理的一些笔记

里面包含一些自己的理解,主要发表目的忘了的时候自己看,如果以后发现写的还好的话再修改一下,推荐给学弟学妹们

发现得声明一下,本文章的东西很多引自 ‘’深入理解Java虚拟机‘’ 这本书,有些好理解的话我基本没改。。。一些地方加上了点自己的理解


目前有三大Java虚拟机:HotSpot,oracle JRockit,IBM J9。

java虚拟机在执行java程序过程中会把它管理的内存分为若干个不同的数据区

运行是常量池,java虚拟机对它没有任何规范,不同的提供商可以自己对这个内存区域进行实现,一般来说除了保存class文件中描述符号引用外
,还会把翻译出来的直接引用直接也存到运行时常量池中,是方法区的一部分。

直接内存,并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。 是通过native函数直接分配堆外内存
然后通过一个存在java堆中的DirectByteBuffer对象为这块内从进行引用操作
JVM中为了解决在native和java中来回复制,为此做了一个缓冲区,用于临时存入某些数据

native native是一个计算机函数,一个Native Method就是一个Java调用非Java代码的接口。方法的实现由非Java语言实现,比如C或C++。

程序计数器 一个较小的内存空间,他可以看做当前线程所执行的字节码的行号指示器。就像一个线程下一步应该干什么,我认为这是很小的队列
每个线程都有一个独立的程序计数器,并且是线程私有的、
并且程序计数器所申请的内存是java虚拟机中唯一一个没有超内存异常报错的内存区域
java虚拟机栈描述的是执行java方法的内存模型,每个方法在执行是都会创建一个栈帧,(因为是多线程,可能好多个方法轮着执行//我认为)用于存储局部变量表,操作数栈,动态链接,方法出口等
(虽然不知道说的是什么玩意,但大概就是用于记录一下开个内存啊   什么时候结束啊什么的,大概还有点怎么执行,执行到哪里什么的)
java虚拟机栈和计数器一样是线程私有的

java虚拟机栈下的局部变量表
里面存了基本数据类型的相关信息,如果创建了什么类的话,它也会加载类里面的相关信息(当然这些信息存到了一个规定的类中 , reference 类型) 和returnAddress
当一个方法入栈是java虚拟机需要确定需要分配多大的内存。


本地方法栈
JVM中没有对其什么强制规定,因此可以再具体的虚拟机自由实现它,(也就是意味着java可以较容易的来编译其他语言的文件),其中主要调用native函数
java堆
是JVM中管理的内存中最大一块 这个内存区的主要目的就是存放实例对象,并且是垃圾收集器管理的主要区域,因此很多时候也被叫做CG堆。
方法区
在Java虚拟机中,方法区是可供各线程共享的运行时内存区域。在不同的JDK版本中,方法区中存储的数据是不一样的。在JDK1.6及之前,运行时常量池是方法区的一个部分,同时方法区里面存储了类的元数据信息、静态变量、即时编译器编译后的代码(比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等)等。在JDK1.7及以后,JVM已经将运行时常量池从方法区中移了出来,在JVM堆开辟了一块区域存放常量池。

是各个线程共享的内存区域 , 它用于存储已经被加载过了的类信息、常量、编译后的代码等数据。java虚拟机将他描述为一个逻辑部分
它有个别名叫非堆 目的是和java堆区分开
它对回收的条件非常苛刻  所以需要专门去写回收内存的检测,否则会内存泄漏。比如spring 使用IOC或者AOP创建bean时,或者使用cglib,反射的形式动态生成class信息等

对象的创建

对象的创建
当对象被建立的时候首先java虚拟机先去检查常量池是否已经被加载,解析,初始化。如果没有才进行加载 如果有那么直接用
java堆中的内存非常规整,左侧为被占用的内存,右侧为未被占用的内存,在两个中间有个指针来划分界限,当有内存请求的时候则向右移动指针分配内存。这种分配方式被称为“指针碰撞”
在给对象分配内存时有可能出现一种问题  就是在更改A内存指针的时候,还没改完,B也申请了内存并且执行,这时读到的内存状态是没改的状态,而A读的也是没改的状态,就可能出现
A和B被分配到了同一块内存地址,导致数据丢失。有点像线程中的ABA问题。对此有两种方案去解决这个问题,采用CAS配上失败重试保证更新操作的原子性,(原子性具体的去看线程安全)
CAS就是记录这个点的值,之后赋值的时候查看一下是否相等,相等的时候再进行更改。但是会遇到ABA问题,所有有个升级版就是加上时间戳。
在内存被分配之后便会对这一段内存全部初始化为零值,这保证了java代码可以不赋初始值就直接使用。然后就是java的对象头的一些设置。
到这里对于java虚拟机来说对象已经创建完了,但是对于java程序来说程序员的初始化方法还没有进行,所以在执行到new指令会把init方法执行,也就是我们常用的构造函数。

对象的内存布局
对象在内存中存储的布局可以分成三块区域,对象头(就是记录很多小的属性,具体是什么不多解释),示例数据(Instance Data),对齐填充(Padding)。
对象头部分就是记录一些小的但很必要的东西,如这个对象是哪个类的实例
示例数据是java对象中的主要部分,里面放了大部分主要的内容。
而对齐填充区域,不是很重要,干的事情就是补齐,补齐原因是因为HotSpot VM 的自动内存管理系统要求对象起始地址必须是8字节的整数倍。
(这部分可以联想一下网络中的报文的分区方式,某种意义上很像,可能说的有些不严谨。。)

32bit 和64bit的区别
就是cpu每次处理的字节长度是32位还是64位(当然这只是最浅的理解。。)

对象的访问定位
创建对象当然是为了使用对象
java程序需要在栈上的reference来操作对上的具体对象。

reference
某种意义上的指针
java和c++中有不同的定义
其中一个区别就如c++中reference不能为空,而java中确实想为空就为空(蒙多,想到哪里,就到哪里)(别问我为什么我的文字带声音 O(∩_∩)O哈哈~)
一些见解引自(http://www.cnblogs.com/winkey4986/p/3602295.html)

你可能感兴趣的:(JVM笔记整理)