java内存

java动态运行时区域包括:方法区、虚拟机栈、本地方法栈、堆、程序计数器,如右图所示:
 
程序计数器
程序计数器用来标识要执行的代码的行号,为线程私有
 
虚拟机栈
为线程所私有
虚拟栈里存放的东西?跟线程有关?存放方法信息,包括方法名,方法参数,返回值地址等
存放局部变量表,操作数栈,动态链接,方法出口等信息
存在两种异常:
a.StackOverflowError(栈溢出异常),当方法深度大于栈深度时(如果线程请求的栈深度大于虚拟机所允许的深度)
b.OutOfMemory(内存溢出)没有更多的空间来存放线程空间
 
本地方法栈
和虚拟栈类似,区别是虚拟栈存储虚拟机方法,本地方法栈存储本地方法堆,几乎所有的对象都在堆中产生。
堆是GC的重点区域。根据对象特点可分为新生代和老年代。其中新生代又可以划分为eden,survivior1,survivor2
 
方法区
各个线程所共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
在HotSpot中,方法区又叫做永久代。存放一些不变的信息。类信息,常量,,,存在OOM异常
 
直接内存
OOM异常
在JDK1.4中新加入了NIO类,引入了一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native中来回复制数据的开销。
 
常量池
String. intern()方法
如果常量池中存在该变量,则返回常量池中变量的指针引用。否则,把该变量添加进常量池,并返回该常量池的指针引用。
运行时常量是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息以外,还有一项信息是常量池,用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
 
对象的创建

1.判断类是否加载,如果没有加载,需要加载类信息。加载完类信息以后,对象创建需要分配的内存空间是确定的。

2.为对象分配内存空间

如果可分配内存空间是连续的,则只需要在可用空间移动指针。(指针碰撞[Bump the Point])

如果可分配内存空间是不连续的,则需要维护一个剩余空间的指针列表。(空闲列表[Free List])

剩余空间是否连续与所采用的GC算法有关。例如:使用标记-清除算法(MS)剩余空间碎片不连续,使用复制算法或者标记-整理(mark-compact)算法剩余空间是连续的。

3.在堆中创建对象是很频繁的行为,所以需要确保在多线程中分配空间的安全性。有两种方式:

a.失败重试和CAS保证

b.虚拟机本地线程缓存(本地线程分配缓存[Thraed Local Allocation Buffer TLAB]),就是给每个线程分配一段内存空间,只有线程内存空间使用完或者不够新对象内存分配时才会涉及到线程之间的竞争。

4.对象初始化

分配完内存空间后,JVM会对新分配的对象进行初始化。基本数据类型被赋值为类型的初始值。

5.按照开发人员的编码初始化。

对象的访问定位

有两种方式

1.直接引用 直接指针

2.间接引用 使用句柄

 
优缺点
直接引用效率更快,间接引用在更改对象引用后不用修改指针引用。
使用直接指针最大的好处是速度快,因为它节省了一次指针定位的时间开销。
使用句柄访问的最大好处是reference中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。

内存溢出

堆内存溢出

产生原因:堆中没有足够多的内存完成空间分配,并且无法扩展
限制参数:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError

实例代码:

public class HeapOoMException {
public static void main(String[] args) {
List<String> out = new ArrayList<String>();
for (int i = 0; i < 16; i++) {
out.add(_1MB._1Mb());
}
} public static String _1Mb() {
int kb = 1024;
int mb = 512 * kb;
char[] chars = new char[mb];
Arrays.fill(chars, 'f');
return new String(chars);
}
}

栈内存溢出

产生原因:线程请求栈深度大于虚拟机所允许的最大深度

限制参数:-Xss128k

实例代码:

public class StackOverFlowException {

    private static long stackLength = 0;

    public static void main(String[] args) throws Throwable {
StackOverFlowException sof = new StackOverFlowException();
try {
sof.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:" + stackLength);
throw e;
}
} private void stackLeak() {
stackLength++;
stackLeak();
}
}

 方法区溢出

产生原因:由于动态代理等导致的类信息容量大于方法区容量
限制参数:-XX:PermSize=10m -XX:MaxPermSize=10m

实例代码:

public class VmMethodException {
public static void main(String[] args) {
while (true) {
Enhancer enhance = new Enhancer();
enhance.setSuperclass(OomObject.class);
enhance.setUseCache(false);
MethodInterceptor mi = new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
throws Throwable {
return methodProxy.invoke(o, objects);
}
};
enhance.setCallback(mi);
enhance.create();
}
} static class OomObject {
}
}

jvm内存区域与内存溢出的更多相关文章

  1. JVM内存区域与内存溢出异常

    Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域,不同的区域在内存不足时会抛出不同的异常. >>运行时数据区域的划分 (1)程序计数器程序计数器(Progra ...

  2. JVM基础知识(1)-JVM内存区域与内存溢出

    JVM基础知识(1)-JVM内存区域与内存溢出 0. 目录 什么是JVM 运行时数据区域 HotSpot虚拟机对象探秘 OutOfMemoryError异常 1. 什么是JVM 1.1. 什么是JVM ...

  3. 深入理解jvm之内存区域与内存溢出

    文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Hea ...

  4. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  5. 深入理解JVM之JVM内存区域与内存分配

    深入理解JVM之JVM内存区域与内存分配 在学习jvm的内存分配的时候,看到的这篇博客,该博客对jvm的内存分配总结的很好,同时也利用jvm的内存模型解释了java程序中有关参数传递的问题. 博客出处 ...

  6. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  7. 第二章Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...

  8. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  9. 深入了解Java虚拟机(1)java内存区域与内存溢出异常

    java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...

  10. 2.1 自动内存管理机制--Java内存区域与内存溢出异常

    自动内存管理机制 第二章.Java内存区域与内存溢出异常 [虚拟机中内存如何划分,以及哪部分区域.什么样代码和操作会导致内存溢出.各区域内存溢出的原因] 一.运行时数据区域 Java虚拟机所管理的内存 ...

随机推荐

  1. zabbix基本操作

    zabbix基本操作 ---- 2016年终总结 二 包括的内容: 添加主机 查看监控数据 添加监控项 创建触发器 创建模版 添加报警 添加媒介 添加主机 进入页面 点击Configuration(大 ...

  2. centos 7.3二进制安装mariadb10.2.8完美步骤

    (1)在centos7系统上,yum info mariadb可以找到提供mariadb包的官方网站,在到官方网站下载最新的mariadb包,然后rz到linux系统上去 (2)准备用户 1.user ...

  3. Emgu.CV(三)

    像素交换 private void btn_Exchange_Click(object sender, EventArgs e) { if (imageBox1.Image != null) { va ...

  4. 使用 Newtonsoft.Json 操作 JSON 字符串

    一.把实体类转化为 JSON 字符串 1. 为实体类赋值 SenderFromMQSearch senderFromMQSearch = new SenderFromMQSearch(); sende ...

  5. 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结

    虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...

  6. toString方法的用处

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Consolas; color: #a5b2b9 } p.p1 { margin: 0.0px ...

  7. Gridview 动态添加行

    /// <summary> /// 首次加载绑定 /// </summary> private void DataLoad()         { list.Add(new P ...

  8. 数据帧CRC32校验算法实现

    本文设计思想采用明德扬至简设计法.由于本人项目需要进行光纤数据传输,为了保证通信质量要对数据进行校验.在校验算法中,最简单最成熟的非CRC校验莫属了. 得出一个数的CRC校验码还是比较简单的: 选定一 ...

  9. LeetCode 442. Find All Duplicates in an Array (在数组中找到所有的重复项)

    Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others ...

  10. BZOJ-1225-[HNOI2001] 求正整数

    Description 对于任意输入的正整数n,请编程求出具有n个不同因子的最小正整数m.例如:n=4,则m=6,因为6有4个不同整数因子1,2,3,6:而且是最小的有4个因子的整数. Input n ...