转自:http://blog.jobbole.com/104863/

  对于Java程序员你来说,在虚拟机内存管理的帮助下,不需要为每个new对象都匹配free操作,内存泄露和内存溢出等问题也不太容易出现,不过也正是因为把内存管理交给了虚拟机,一旦运行中的程序出现了内存泄露问题,给排查过程造成很大困难。所以只有理解了Java虚拟机的运行机制,才能够运筹帷幄于各种代码。本文以HotSpot为例说说虚拟机的那些事。

JAVA虚拟机把管理的内存划分为几个不同的数据区。

Java堆

Java堆是被所有线程共享的一块内存区域,主要用于存放对象实例,Java虚拟机规范中有这样一段描述:所有的对象实例和数据都要在堆上进行分配。为对象分配内存就是把一块大小确定的内存从堆内存中划分出来,通常有两种方法实现:

1 、指针碰撞法
假设Java堆中内存时完整的,已分配的内存和空闲内存分别在不同的一侧,通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离。

2、空闲列表法
事实上,Java堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM通过维护一个列表,记录可用的内存块信息,当分配操作发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。

对象创建是一个非常频繁的行为,进行堆内存分配时还需要考虑多线程并发问题,可能出现正在给对象A分配内存,指针或记录还未更新,对象B又同时分配到原来的内存,解决这个问题有两种方案:
1、采用CAS保证数据更新操作的原子性;
2、把内存分配的行为按照线程进行划分,在不同的空间中进行,每个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB);

Java栈

Java栈是线程私有的,每个线程对应一个Java栈,每个线程在执行一个方法时会创建一个对应的栈帧(Stack Frame),栈帧负责存储局部变量变量表、操作数栈、动态链接和方法返回地址等信息。每个方法的调用过程,相当于栈帧在Java栈的入栈和出栈过程。

局部变量表 用于存放方法参数和方法内部定义的局部变量,其大小在代码编译期间已经确定,在方法运行期间不会改变。局部变量表以变量槽(Slot)为最小存储单位,每个Slot能够存放一个boolean、byte、char、shot、int、float、reference和returnAddress类型的32位数据,对于64位的数据类型long和double,虚拟机会以高位对齐的方式为其分配两个连续的Slot空间。

在方法执行时,如果是实例方法,即非static方法,局部变量表中第0位Slot默认存放对象实例的引用,在方法中可以通过关键字 this 进行访问,方法参数按照参数列表顺序,从第1位Slot开始分配,方法内部变量则按照定义顺序进行分配其余的Slot。

 class test {
public int calc(int a, int b, String operation) {
operation = "+";
return a + b;
} public void main(String args[]) {
calc(100, 200, "+");
}
}

对应的局部变量表如下:

使用 javap -c 命令查看方法calc的字节码

其中iload_1和iload_2分别从局部变量表中的第1位和第2位中加载数据。

方法区

方法区和Java堆一样,是所有线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码等数据。

运行时常量池是方法区的一部分,用于存放编译期间生成的各种字面常量和符号引用。

指令计数器

指令计数器是线程私有的,每个线程都有独立的指令计数器,计数器记录着虚拟机正在执行的字节码指令的地址,分支、循环、跳转、异常处理和线程恢复等操作都依赖这个计数器完成。如果线程执行的是native方法,这个计数器则为空。

对象的内存布局

对象在内存中布局可以分成三块区域:对象头、实例数据和对齐填充。

1、对象头
对象头包括两部分信息:运行时数据和类型指针,如果对象是一个数组,还需要一块用于记录数组长度的数据。

1.1、运行时数据包括哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID和偏向时间戳等,这部分数据在32位和64位虚拟机中的长度分别为32bit和64bit,官方称为”Mark Word”。Mark Word被设计成非固定的数据结构,以实现在有限空间内保存尽可能多的数据。

32位的虚拟机中,对象未被锁定的状态下,Mark Word的32bit中25bit存储对象的HashCode、4bit存储对象分代年龄、2bit存储锁标志位、1bit固定为0,具体如下:

其它状态(轻量级锁定、重量级锁定、GC锁定、可偏向锁)下Mark Word的存储内容如下:

1.2、对象头的类型指针指向该对象的类元数据,虚拟机通过这个指针可以确定该对象是哪个类的实例。

2、实例数据
实例数据就是在程序代码中所定义的各种类型的字段,包括从父类继承的,这部分的存储顺序会受到虚拟机分配策略和字段在源码中定义顺序的影响。

3、对齐填充
由于HotSpot的自动内存管理要求对象的起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍,对象头的数据正好是8的整数倍,所以当实例数据不够8字节整数倍时,需要通过对齐填充进行补全。

JVM 内存的那些事的更多相关文章

  1. JVM内存的那些事

    前言 对于C语言开发的程序员来说,在内存管理方面,必须负责每一个对象的生命周期,从有到无. 对于Java程序员你来说,在虚拟机内存管理的帮助下,不需要为每个new对象都匹配free操作,内存泄露和内存 ...

  2. JVM内存划分基础知识

    第一部分 JVM内存划分 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbag ...

  3. Inside JVM 内存模型

    Inside JVM 内存模型 来源  原文:https://blog.csdn.net/silentbalanceyh/article/details/4661230 参考:IBM开发中心文档,&l ...

  4. JVM内存GC的骗局——JVM不抛出OOM但内存已经泄露

    概述 在日常测试中,我们会去重点观察java的内存使用情况,比如:进程会抛出OOM异常,不再接收新的请求:响应时间在固定时间段内变长,超时或者不响应,CPU使用率时常像过山车一样等.有时候JVM还会发 ...

  5. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  6. 第八章 JVM内存管理

    8.1 物理内存与虚拟内存 地址总线(连接处理器和RAM或处理器和寄存器的)的宽度影响了物理地址的索引范围,决定了处理器一次可以从寄存器或内存中获取多少个bit.同时决定了处理器最大的寻址空间,32位 ...

  7. JVM内存模型 三

    本文章节: 1.JMM简介 2.堆和栈 3.本机内存 4.防止内存泄漏   1.JMM简介 i.内存模型概述 Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉 ...

  8. JVM内存GC的骗局

    此文已由作者尧飘海授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 概述 在日常程序开发中,很多JAVA程度员不太关心内存的使用情况.当然,如果程序员运气较好或者系统没有大规模 ...

  9. 谈谈JVM内存区域的划分

    我们知道,计算机CPU和内存的交互是最频繁的,内存是我们的高速缓存区,用户磁盘和CPU的交互,而CPU运转速度越来越快,磁盘远远跟不上CPU的读写速度,才设计了内存,用户缓冲用户IO等待导致CPU的等 ...

随机推荐

  1. UVA1003(dfs+进制转换)

    题意:输入很多字符的16进制数,现在需要你先转化为2进制,之后二进制中1和0组成的字符需要你求出来. 思路:字符每一个都有所不同可以靠圆圈的数目求出. #include<cstdio> # ...

  2. Android EidtText 光标的使用和设置

    使光标移动到制定的位置: editText.setSelection(editText.length()); 输入的参数是个整数   在请求出现光标是,也就是在获取焦点时: editText.requ ...

  3. 在不安装mysql-connector-net的情况下使用FluentData框架

    最近在开发项目中使用了FluentData框架,通过使用这个框架减少了很多开发的工作量,FluentData是一个轻量级的框架操作起来的自由度很大也少了很多负责的配置.但是在开发的时候发现一个问题就是 ...

  4. python整理之(字符串、元组、列表、字典)

    一.关于字符串的整理总结 对于字符串的操作常用的有这些: 字符串的操作通过dir()函数可以查看 我们先整理没有下划线的用法,有下划线的暂时不去考虑. 1.capitalize 功能:使字符串的首字母 ...

  5. zabbix问题处理

    工作的时候回遇到各种各样的问题. 今天遇到一个关于zabbix的问题. "Zabbix agent on host.name is unreachable for 5 minutes&quo ...

  6. Python>>>The Very First Step

    Windows官网下载 python-2.7.13.amd64.msi 默认会安装pip,同是把设置环境变量也选中 安装第三方包: pip install pygame 确认已经正确安装的方法:1.完 ...

  7. mysql总结

    //查询日期之前的差距     select user_name ,    from_unixtime(user_lastlogin_time),now() ,        year(now())- ...

  8. DevWebForm控件,触发用客户端事件

    ClientInstanceName+".Raise"+"事件名", 例如: ClientInstanceName.RaiseValueChanged();

  9. 关于页面里没有id属性的Javascript上的解决办法

    如果页面上只有Textarea,可以用如下方法来遍历其name属性然后赋给id属性:<script> try{ window.onload = setTextAreaIds();setTe ...

  10. javascript Date

    转:http://blog.csdn.net/vbangle/article/details/5643091# // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日( ...