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. thinkphp5.0解决控制器驼峰命名时提示找不到类名

    今天碰到了一个比较坑爹的问题,我的控制器的名字是用驼峰命名的,但是却给我报错,如下: 怎么解决呢? 看我的视图,同样是驼峰命名,此时只要将其改为auth_group这样的方式就可以了. 注意:url地 ...

  2. 使用Gradle构建Android项目

    阅读目录 Gradle是什么? 环境需求 Gradle基本结构 任务task的执行 基本的构建定制 目录配置 签名配置 代码混淆设置 依赖配置 输出不同配置的应用 生成多个渠道包(以Umeng为例) ...

  3. vue.js实例对象+组件树

    vue的实例对象 首先用js的new关键字实例化一个vue el: vue组件或对象装载在页面的位置,可通过id或class或标签名 template: 装载的内容.HTML代码/包含指令或者其他组件 ...

  4. Hadoop(九)Hadoop IO之Compression和Codecs

    前言 前面一篇介绍了Java怎么去查看数据块的相关信息和怎么去查看文件系统.我们只要知道怎么去查看就行了!接下来我分享的是Hadoop的I/O操作. 在Hadoop中为什么要去使用压缩(Compres ...

  5. 使用Angularjs和Vue.js对比

    使用Angularjs和Vue.js对比 之前项目都是使用Angularjs,(注明此处主要讲Angularjs 1)在初步使用Vue.js后做一个简答的对比笔记. 首先从理论上简单说一下各自的特点, ...

  6. time函数获取时间与本地时间不一致

    修改php.ini,将“date.timezone”项修改为“date.timezone = PRC”. 大陆内地可用的值是:Asia/Chongqing ,Asia/Shanghai ,Asia/U ...

  7. Mybatis报错:Parameter 'list' not found. Available parameters are [groupList, param1]

    GroupDao.java 里面定义的方法: void batchInsertLog(@Param("groupList") List<MktPromotionIntegra ...

  8. CentOS7安装GitLab、汉化、邮箱配置及使用

    同步首发:http://www.yuanrengu.com/index.php/20171112.html 一.GitLab简介 GitLab是利用Ruby On Rails开发的一个开源版本管理系统 ...

  9. sudo使用详细讲解

    1.原因:让普通用户具有root用户的权限通过sudo执行的命令都会存在日志里面2.用法1.sudo -l 列出当前用户有哪些sudo权限 2.visudo -c 检查语法是否错误 3.visudo ...

  10. Linux学习(十六)VIM

    一.简介 VIM是vi的增强版.VIM是Linux平台上的主要编辑器.基本上所有的文档的新增,修改,保存都需要用到它.所以,掌握VIM是很有必要的. vim的安装非常简单,一条命令就可以了: yum ...