zoukankan      html  css  js  c++  java
  • JAVA的堆栈和内存、垃圾回收解说

    1.有关java健壮性特点的真相

    很多书上都说java健壮性的特点是因为java使用数组代替了c++的指针;c++最令人头痛的问题就是内存问题,java的健壮性使编程人员不用再考虑内存的问题;这种观点和想法是不对,java虽然有垃圾回收机制,不需要程序员去delete内存,但是在编码的时候还是应该考虑到内存的,尽量不要去浪费jvm的内存;这里就涉及到了java的堆栈问题。

    2.java堆栈的区别

      堆:存放类类型,用new建立,垃圾自动回收机制负责回收,速度慢

    1).堆是一个“运行时”数据区,类实例化对象是从堆上去分配空间的,也就是说堆上空间都是通过new指令建立的;

    2).与c++的区别就是java不需要显示的去释放堆,而是由垃圾回收机制负责,这是因为堆是动态分配内存大小的,即程序运行的时候分配;

    3).这也产生了一个问题,堆空间的数据内存读取比较慢。

        例:String str =new String(“yangkai”);

      栈:存放基本数据类型,速度快

    1).栈主要存放基本数据类型(byte、short、int、long、float、double、boolean、char)和对象句柄;

    2).数据可以共享;何为共享?这里说的共享不是程序员决定的而是由jvm来控制,指系统自动处理的方式,比如说:int a = 10;int b= 10;这里的a、b变量指向的栈上空间地址是同一个,这就是所谓的“数据共享”;jvm的处理逻辑:java虚拟机去处理int a = 10的时候先去栈上创建一个变量作为a的引用,然后去查栈去找有没有10的值,如果有就将a指向10,如果没有就把10存进来。

    3).相对于堆来说速度快;

    4).栈数据的大小与生存期是确定的,缺乏灵活性。

    例:int a = 0;

    3.实例化对象的方法

      比如说String这个类的实例可以由两种方法建立:

    String str = new String(“yangkai”);

    String str = “yangkai”;

       分析:这两个方式创建的额对象是不同的,依照咱们上面介绍的堆栈知识应该对这种String的实例有所了解了吧!第一种采用new方式的在堆上开辟空间没调用一次就会创建一个对象;第二种是现在栈上创建String对象的引用,然后存储“yangkai”再让str引用;下次再调用str,如果栈上有就不会再次创建了;所以一般比较String变量的时候都采用两种方式,equals()和“==”;一般“==”判断的是对象是否相等即是否是同一个对象;判断出来两个String对象相等了说明这个字符串是存放在栈的,数据是共享的,这两个字符串是同一个对象;而equals()判断两个对象的内容是否相等,比如判断堆上的字符串的内容只能通过equals()方法来判断,“==”判断的可能是false,因为每一个string在堆上都是以一个String对象存储的。

    4.如何控制内存,这里教你查看jvm内存的使用

    当前虚拟机的最大内存: Runtime.getRuntime().maxMemory();

    循环前虚拟机已占内存: Runtime.getRuntime().totalMemory();

       下面使用两个案例来监测jvm内存:

    package com.hudong.memory;
    /**
     *
     * @Title: MemoryTest.java
     * @Copyright: Copyright (c)2005
     * @Description: <br>
     * <br>
     *              测试java虚拟机的内存占用情况
    * @Created on 2014-1-21 上午11:40:35
     * @author杨凯
     */
    public class MemoryTest {
     
        /**
        * @param args
        */
        public static void main(String[]args) {
           testStringBuffer();
           // testString();
        }
     
        /**
        * 测试String实例对象的占用的内存
        */
        public static void testString() {
           String str = new String("abcdefghijklmn");
           int count = 0;
           System.out.println("当前虚拟机的最大内存:" + Runtime.getRuntime().maxMemory()/ 1024 / 1024 + "m------" + Runtime.getRuntime().maxMemory()+ "byte");
           System.out.println("循环前虚拟机已占内存:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
           while (true) {
               try {
                    str += str;
                    count++;
                } catch (Error e) {
                    System.out.println("循环次数:" + count);
                    System.out.println("字符串循环后的大小为:" + str.length() / 1024 / 1024 + "m-=-=-=" + str.length() + "byte");
                    System.out.println("循环前虚拟机已占内存:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
                    System.out.println("遇到错误:" + e);
                    break;
               }
           }
           /*
            * 运行结果:
            * 当前虚拟机的最大内存:793m------832438272byte
               循环前虚拟机已占内存:127m====133234688byte
               循环次数:23
               字符串循环后的大小为:112m-=-=-=117440512byte
               循环前虚拟机已占内存:642m====673669120byte
               遇到错误:java.lang.OutOfMemoryError: Java heap space
            */
        }
     
        /**
         * 测试StringBuffer实例对象的占用的内存
        */
        public static void testStringBuffer(){
           StringBuffer sb = new StringBuffer("abcdefghijklmn");
           int count = 0;
           System.out.println("当前虚拟机的最大内存:" + Runtime.getRuntime().maxMemory()/ 1024 / 1024 + "m------" + Runtime.getRuntime().maxMemory()+ "byte");
           System.out.println("循环前虚拟机已占内存:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
           while (true) {
               try {
                    sb.append(sb);
                    count++;
               } catch (Error e) {
                    System.out.println("循环次数:" + count);
                    System.out.println("字符串循环后的大小为:" + sb.length() / 1024 / 1024 + "m-=-=-=" + sb.length() + "byte");
                    System.out.println("循环前虚拟机已占内存:" + Runtime.getRuntime().totalMemory()/ 1024 / 1024 + "m====" + Runtime.getRuntime().totalMemory()+ "byte");
                    System.out.println("遇到错误:" + e);
                    break;
               }
           }
           /*
            * 运行结果:
            * 当前虚拟机的最大内存:793m------832438272byte
               循环前虚拟机已占内存:127m====133234688byte
               循环次数:23
               字符串循环后的大小为:112m-=-=-=117440512byte
               循环前虚拟机已占内存:539m====566108160byte
               遇到错误:java.lang.OutOfMemoryError: Java heap space
     
            */
        }
    }


       分析:以上两个程序用来说明String和StringBuffer两个占用内存的情况;其他资料上面介绍这两个类的使用的时候得出的结果是:Stringbuffer比String循环后得到的字符串字节大;而我在这测试的时候得到结果两个类得到的字符串大小是一样的,区别是耗费的额虚拟机的内存大小不一样,后者明显的比前者小。

      注:安装完jdk之后jvm默认的大小是63m,上面我测试的时候是将jvm的配置文件的xmx大小调大之后的。

  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/yangkai-cn/p/4016693.html
Copyright © 2011-2022 走看看