[jvm解析系列][一]Java内存区域分配和内存溢出异常OOM

原创 2016年06月02日 10:48:18

学过操作系统的同学应该比较清楚,一个操作系统必须要有完善的内存管理系统(页/段式的管理),相应的jvm全称java虚拟机应该也有类似的一种管理内存的方式,这种方式是建立在真实的操作系统内存管理方式之上的,他把内存分配成了不同的区域,形成了java内存模型。

那么,对于其他博客讲解这种题目要先抛一个图解出来,我并不想这样。因为这种模型的出现肯定是要解决问题的,我们需要顺延着前人设计jvm内存模型的脚步,看看到底为什么要这样设计,才能更好的理解它。

首先,我们思考一下,java需要什么区域呢?

1、必不可少的,一个程序计数器,用来记录当前程序运行的字节码指令,jvm使用了栈而不是寄存器结构(往后看相信你会理解的)。对于线程来讲,每个线程肯定是需要记录自己的执行位置,所以程序计数器是线程私有的

2、既然有了程序计数器我们还需要一个区域来存放当前运行的程序,那就是Java虚拟机栈,每一个方法的执行就会添加一个栈帧在虚拟机栈里(如果想要详细的了解栈帧请关注博客,随着系列的加深,我会一个个讲解)。对于线程来讲虚拟机栈同样的是线程私有。

3、一样的常用jvm的都知道还有一种jni的调用,为了这种方法的运行,设计了一种跟java虚拟机栈的双胞胎区域叫本地方法栈,除了运行native方法外其他的几乎一致。(在有的虚拟机里不区分native和java)

4、大家都知道java是面向对象的,既然方法都出来了,那么类存储在那呢?没错,jvm也分化出来了这样的一个区域叫做方法区(也称为永久代,因为这个区域很长时间不会发生gc)。这个区域里存储了虚拟机家在的所有的类信息,常量和静态变量等。(内含一个运行时常量池主要用于存放编译器生成的字面量和符号引用)他是线程公有的。

5、如果类都有了,那么对象呢?没错这就是jvm的重头戏,很多工作都在这个地方完成,他就是传说中的java堆,在有的地方甚至把jvm笼统的分为堆栈,可见java堆的重要性。java堆里面存放了几乎所有的对象实例,在java虚拟机规范中这样说:所有的对象实例和数组都要在堆上分配。随着JIT编译器等的发展也不那么绝对了。(java堆仍然很复杂,后期单开一篇博客详解)。它肯定是线程公有的。

6、到这里,好像java所有的需要都被分配了,以前确实是的,但是在JDK1.4之后,java引入了nio技术(不在本章范围内讲解),这就要求需要分配一个新的区域,没错,他叫直接内存。值得一提的是,这一区域并不是jvm的规范中的一部分,也不是虚拟机运行时数据区的一部分,但是他会引起OOM。

那么至此所有的内存区域分配完毕,配图如下帮助理解,相信你已经差不多的了解和理解了jvm分配的方式和目的了。

内存区域分配配图


上节说到~jvm的内存分配,所以对应的应该有6种溢出方式,实际上程序计数器一般不会溢出,我又把两个方法栈合在一起讲,所以溢出的可能性有4种

嘿嘿嘿嘿,我要去考试了,等我回来再补吧~

回来了继续补

1、Java堆溢出

java堆溢出一般都是因为在for或者递归里调用了太多次new对象的操作,并且可以被GCROOT查找到不能GC,而导致java堆内存不足报错,报错一般如下:

OutOfMemoryError:Java heap spce

2、虚拟机栈和本地方法栈溢出

虚拟机栈和本地方法溢出一般也是陷入了无限循环里并且在无限循环里一直在调用一个方法,因为一般情况下栈深能有1000~2000,报错一般都是StackOverflowError,OOM反而不常见,在处理这种异常时很棘手,需要减少其他区域的内存,因为这块内存是用总内存减去堆和方法区得到的。报错如下:

StackOverflowError.

3、方法区和运行时常量池溢出

这个区域想要溢出单单使用创建类的方法和常量是困难的,所以可以使用String.intern()方法直接将字符串加入到常量池。报错一般如下

OOM:PermGen space

4、本机直接内存溢出

由于上文知道直接内存一般用于NIO操作,所以使用了native方法而且因为这个区域的特殊性Heap dump并没有明显的报错。错误信息如下:

OutOfMemory。

版权声明:本文为博主原创文章,未经博主允许不得转载。

[jvm解析系列][二]Java堆的详细讲解和对象的分配过程和访问

上回说到Jvm内存的分配,犹如划地分治,把一块本机内存分裂成了6块。 这回我们就讲讲java堆的详细信息 java堆里也不是铁板一块,类似jvm的分治,java堆内部也好不到哪里去,大致上可以分成新生...

Redis系列-存储篇hash主要操作函数小结

阳光透过玻璃,洒在身上,一杯暖茶在手,说不尽的安逸自得,让我有种想再写篇blog的冲动。上篇主要谈了string,这里谈谈hash吧! hash是一些列key value(field value)的...

[jvm解析系列][四]Java的垃圾回收(二)垃圾收集算法,内存分配和回收策略

上回说到如何鉴别一个垃圾。 这回咱们讲讲怎么收集垃圾收集垃圾有几种算法如下: 1、标记-清除算法 这个算法最为基础,我们先讲算法再说优缺点。 实现过程: 标记出所有需要回收的对象,当标记完成...

[Android进阶]Java、Android 内存泄漏总结

Java、Android 内存泄漏总结内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,就是该被释放的对象没有释放,一直被某个或某些实例...

[Java虚拟机]Java内存模型与线程

深入理解Java虚拟机读书笔记第12章主内存和工作内存java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。为了获得较好的执行效能,J...

JVM 学习笔记1 JAVA内存区域与溢出异常

一、运行时数据区 图  HotShot虚拟机内存模型 1、程序计数器(Program Counter Register) 线程隔离的数据区 内容: 一块比较小的内存空间可以看作当前线...
  • yameing
  • yameing
  • 2014年06月02日 23:09
  • 1723

JVM笔记1_java内存区域与溢出异常

1,jvm的自动内存管理机制 2,jvm 运行时数据区域       jvm在执行java程序的过程中将其管理的内存划分为      方法区,存放已经被虚拟机加载的类信息,常量,静态变量,即时编译器编...

【JVM】Java内存区域与OOM

引入Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来。Java虚拟机运行时数据区如图所示1.程序计数器(线程私有) 作用 记录当前线程所...

JVM系列1:java内存区域分配

java内存区域图示: 具体区域分配如下:一.程序计数器1.定义  程序技术器,是一块较小的内存区域。它的作用可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就...
  • a910626
  • a910626
  • 2016年02月28日 17:51
  • 358
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[jvm解析系列][一]Java内存区域分配和内存溢出异常OOM
举报原因:
原因补充:

(最多只允许输入30个字)