在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java内存区域与内存溢出异常

2017-2-7 13:40| 发布者: zhangjf| 查看: 553| 评论: 0

摘要: Java虚拟机运行时数据区 程序计数器 程序计数器可以看作是当前线程所执行的字节码的行号指示器线程私有异常:唯一一个java虚拟机规范中没有规定任何OutOfMemoryError情况的区域复制代码Java虚拟机栈线程私有,生命 ...
Java虚拟机运行时数据区

程序计数器
  1. 程序计数器可以看作是当前线程所执行的字节码的行号指示器
  2. 线程私有
  3. 异常:
  4. 唯一一个java虚拟机规范中没有规定任何OutOfMemoryError情况的区域
复制代码
Java虚拟机栈
  1. 线程私有,生命周期和线程相同
  2. 虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放了编译期可知的各种基本数据类型、对象引用。
  3. 异常:
  4. 线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError异常
  5. 如果虚拟机栈可以动态扩展,如果扩展无法申请到足够的内存,就会抛出OOM
复制代码
  1. /**
  2. * 虚拟栈递归调用栈溢出(StackOverFlowError)
  3. * VM Args:-Xss512k
  4. */
  5. public class JavaVMStackSOF {
  6. private int stackLenqth = 1;
  7. public void stackLeek() {
  8. stackLenqth++;
  9. //递归调用
  10. stackLeek();
  11. }
  12. public static void main(String[] args) {
  13. JavaVMStackSOF stackSOF = new JavaVMStackSOF();
  14. stackSOF.stackLeek();
  15. }
  16. }
  17. //结果
  18. Exception in thread "main" java.lang.StackOverflowError
  19. at outofmemory.JavaVMStackSOF.stackLeek(JavaVMStackSOF.java:11)
复制代码
  1. /**
  2. * 创建线程导致OOM
  3. * VM Args: -Xss2M
  4. */
  5. public class JavaVMStackOOM {
  6. private void dontStop(){
  7. while (true){
  8. }
  9. }
  10. public void stackLeakByThread(){
  11. while (true){
  12. Thread thread = new Thread(new Runnable() {
  13. public void run() {
  14. dontStop();
  15. }
  16. });
  17. thread.start();
  18. }
  19. }
  20. public static void main(String[] args) {
  21. JavaVMStackOOM stackOOM = new JavaVMStackOOM();
  22. stackOOM.stackLeakByThread();
  23. }
  24. }
  25. //结果
  26. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
复制代码
本地方法栈
  1. 所有线程共享
  2. 本地方法栈和Java虚拟栈相似,Java虚拟机栈为虚拟机执行Java方法(字节码)服务,本地方法栈为虚拟机
  3. 用到的native方法服务。
  4. HotSpot虚拟机将虚拟机栈和本地方法栈合二为一
复制代码
Java堆
  1. 所有的对象实例和数组都要在堆上分配
  2. Java堆是垃圾器管理的主要区域
  3. 异常:
  4. 堆中没有内存完成实例分配,并且堆无法在扩展的时,就会抛出OOM
复制代码
  1. /**
  2. * 堆内存溢出
  3. * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
  4. */
  5. public class HeapOOM {
  6. static class OOMObject {
  7. }
  8. public static void main(String[] args) {
  9. List<OOMObject> list = new ArrayList<OOMObject>();
  10. while (true) {//循环创建对象
  11. list.add(new OOMObject());
  12. }
  13. }
  14. }
  15. //运行结果
  16. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
复制代码
方法区
  1. 所有线程共享
  2. 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  3. 异常:
  4. 方法区无法满足内存分配需求时,就会抛出OOM
复制代码
运行时常量池
  1. 方法区的一部分
  2. 用于存放编译期生成的各种字面量和符号引用
  3. Java并不要求常量一定要是编译期才能产生,运行期间也可能将新的常量放入池中,比如String类的intern()方法
  4. 异常:
  5. 运行时常量池作为方法区的一部分,自然收到方法去内存的限制,常量池无法申请到内存抛出OOM
复制代码
  1. /**
  2. * 运行是常量池溢出
  3. * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
  4. */
  5. public class RuntimeConstantPoolOOM {
  6. public static void main(String[] args) {
  7. List<String> stringList = new ArrayList<String>();
  8. int i = 1;
  9. while (true){
  10. stringList.add(String.valueOf(i++));
  11. }
  12. }
  13. }
  14. //结果
  15. Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M;
  16. support was removed in 8.0
  17. Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M;
  18. support was removed in 8.0
  19. // 分析
  20. 我使用的时jdk8.0发生如上错误,这个说明永久代已经在java8.0中被移除,被元空间替代。
  21. 关于为啥要移除替代本篇不累赘。如果使用的jdk8.0一下版本则会出现OOM:PermGen space
  22. 这样可以证明常量池属于方法区
  23. //VM Args:-XX:MaxMetaspaceSize=2M(这样设置元空间大小 )
复制代码
直接内存
  1. 直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域
  2. NIO可以使用Native函数库直接分配堆外内存
  3. 异常:
  4. 本机内存不足抛出OOM
复制代码

参考资料:《深入理解Java虚拟机》

来自: http://my.oschina.net/u/2361475/blog/600000

上一篇:jstack命令下一篇:Java 8的八个新特性

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 04:22

Copyright 2015-2025 djqfx

返回顶部