zoukankan      html  css  js  c++  java
  • java虚拟机之常见的异常

    1、JAVA堆溢出

    public class HeapOOM {
        HeapOOM[] testlist= new HeapOOM[100000];
        public static void main(String[] args) {
            List<HeapOOM> list= new ArrayList<HeapOOM>();
            while(true){
                list.add(new HeapOOM());
            }
        }
    }
    

      

    2、虚拟机栈和本地方法栈溢出(-Xss:栈内存容量)

      两种异常:

        如果线程请求的深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

        如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

      单线程时栈溢出:

    public class StackOverflow {
        private int stackLength = 1;
        public void stackLeak(){
            stackLength++;
            stackLeak();
        }
    
        public static void main(String[] args) throws Throwable {
            StackOverflow stackOverflowError = new StackOverflow();
            try {
                stackOverflowError.stackLeak();
            }catch (Throwable e){
                System.out.println("stack 深度:"+stackOverflowError.stackLength);
                throw e;
            }
    
        }
    }
    

      多线程下的栈溢出:

        通过不断建立线程的方式可以产生内存溢出异常。在这种情况下,为每个线程的栈分配的内存越大,越容易产生内存溢出异常。

    原因是:操作系统分配给每个进程的内存是有限制的,譬如32位的Windows限制为2GB。虚拟机提供了参数来控制Java堆和方法区的两部分内存的最大值。剩余的内存为2GB减去Xmx(最大堆容量),再减去MaxPermSize(最大方法区容量)

    public class StackOverThread {
        private void donnotStop(){
            while (true){
                donnotStop();
            }
        }
        public void stackLeakByThread(){
            while (true){
                Thread thread = new Thread(new Runnable() {
                    public void run() {
                        donnotStop();
                    }
                });
                thread.start();
            }
    
        }
        public static void main(String[] args) {
            StackOverThread stackOverThread = new StackOverThread();
            stackOverThread.stackLeakByThread();
        }
    }
    

      

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

      String.intern():如果字符串常量池中已经包含了一个等于此String对象的字符串,则返回代表这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

      -XX:PermSize和 -XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的内容。

    public class RuntimeConstantPool {
        public static void main(String[] args) {
            List<String> list = new LinkedList<String>();
            int i = 0;
            while (true){
                list.add(String.valueOf(i++).intern());
            }
        }
    }
    

      报错:  Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

              at java.lang.String.intern(Native Method)
              at com.yhq.chapter1.RuntimeConstantPool.main(RuntimeConstantPool.java:12)

    public class RuntimeConstantPool2 {
        public static void main(String[] args) {
            String str1 = new StringBuilder("计算机").append("软件").toString();
            System.out.println(str1.intern() == str1);
    
            String str2 = new StringBuilder("ja").append("va").toString();
            System.out.println(str2.intern() == str2);
        }
    }
    

        在jdk1.6中会得到两个false,在jdk1.7中会得到一个true和一个false。

        在jdk1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由StringBuilder创建的字符串在Java堆上,所以必然不是同一个引用,将返回false。

        在jdk1.7中,intern()方法实现不会复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。对于str2返回的是false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用,不符合首次出现原则,此时intern()返回的是字符串常量池中的引用,而由StringBuilder创建的字符串在Java堆上,所以必然不是同一个引用,将返回false。

      

  • 相关阅读:
    php 日期处理 DateTime
    http范围请求
    fiddle扩展
    汉字编码 (GB2312 GBK GB18030)
    Navicat http 通道增加验证
    vim 支持 nginx配置文件 语法高亮
    composer 使用
    剖析nsq消息队列(三) 消息传输的可靠性和持久化[一]
    剖析nsq消息队列(二) 去中心化源码解析
    剖析nsq消息队列(一) 简介及去中心化实现原理
  • 原文地址:https://www.cnblogs.com/yaohuiqin/p/9550254.html
Copyright © 2011-2022 走看看