精华内容
下载资源
问答
  • Java内存分配

    千次阅读 2016-03-25 22:30:37
    而对于Java程序员来说,JVM自动进行内存管理,程序员不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出问题。 但是,正因为JVM帮我们管理了内存,一旦出现内存泄露或溢出问题,如果...

    概述

    对从事C和C++的程序员来说,在内存管理方面,他们既是拥有最高权利的人,也是从事最基础工作的“劳动人民”。

    而对于Java程序员来说,JVM自动进行内存管理,程序员不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄露和内存溢出问题。

    但是,正因为JVM帮我们管理了内存,一旦出现内存泄露或溢出问题,如果不了解虚拟机是怎么管理内存的,那么排查错误会成为一项异常艰难的工作

    So, 小伙伴们,走起,让我带你们进入JVM的内存世界!


    运行时数据区域(Run-Time Data Areas)

    首先,叫“Java内存分配”并不是我本意,我是为了能让大家搜索进来才起的这个名字,Java(JVM)关于内存的管理是一个叫:“运行时数据区”的章节

    JVM在运行时(运行时就是执行Java程序时)根据《Java虚拟机规范(Java SE 7)》的规定,会包括如下几个运行时数据区域

    这里写图片描述


    1. 程序计数器(Program Counter Register)

    或者叫:程序计数寄存器、PC寄存器,学过计算机组成原理应该就懂

    a. 作用

    1. 程序计数器是一块较小的内存空间,可以看做是当前线程(Thread)所执行的字节码的行号指示器

      在JVM概念模型中(各种JVM可能并不依照此开发),解释器(Interpreter)就是通过改变这个计数器的值来选取下一条需要执行的字节码指令

    2. 为了在线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器。这种内存区域称为“线程私有”的内存

    3. 线程正在执行Java方法时,计数器记录的是虚拟机字节码指令的地址;如果执行的是Native方法,则计数器值为空(Undefined)

    b. Error

    这块内存是JVM规范中唯一没有规定任何OutOfMemoryError的区域


    2. 虚拟机栈(Virtual Machine Stacks)

    也是线程私有的,其生命周期和线程一样,每个Java线程有一个虚拟机栈

    a. 作用

    虚拟机栈描述的是Java方法执行的内存模型,即:每个方法在执行的时候都会创建一个栈帧(Stack Frame),栈帧中存储:

    1. 局部变量表

      1. 存放了编译期就可知的:各种基本数据类型(8个基本数据类型)、对象引用、returnAddress类型(指向一条字节码指令地址)
      2. 局部变量表所需的内存大小在编译期就完成了分配,也就是说当进入一个方法时,此方法需要在栈帧中分配多大的局部变量表空间时完全确定的,运行期不会改变
    2. 操作数栈

    3. 动态链接

    4. 方法出口等

    方法从调用到执行完成的过程,就对应了,一个栈帧在虚拟机栈中的入栈和出栈的过程

    b. Error

    有两种异常:
    1. 如果线程请求的栈深度大于JVM所允许的深度,将抛出StackOverflowError异常
    2. 如果栈扩展时无法申请到足够的内存,将抛出OutOfMemoryError异常


    3. 本地方法栈(Native Method Stack)

    a. 作用

    作用和虚拟机栈基本一样,只不过这里为Native方法服务
    JVM规范没有强制规定本地方法栈中的方法使用的语言、使用方式、数据结构,所以具体JVM不同实现

    HotSpot虚拟机直接把虚拟机栈和本地方法栈合二为一了

    b. Error

    如1.2的虚拟机栈一样


    4. Java堆(Java Heap)

    基本上Java堆是虚拟机管理的内存中最大的一块。是被所有线程共享的一块区域,在虚拟机启动时创建,通过参数“-Xmx和-Xms”控制

    a. 作用

    所有对象实例和数组都要在堆上存放(例外的情况在我另一篇博客有描述JVM - JIT编译器 - 6.1
    Java堆是垃圾回收器管理的主要区域

    b. 分类

    下面是一些具体的细分,但是不论如何分类,其存储的仍然是对象实例,进一步划分的目的是为了更好的回收、更快的分配内存

    1. 从内存回收的角度看

    由于现代GC基本都采用分带收集算法,所以Java堆还可以细分为:

    1. 新生代
    2. 老年代

    再细分一下还可分为:

    1. Eden空间
    2. From Survivor空间
    3. To Survivor空间

    2. 从内存分配角度看

    线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)

    c. Error

    如过堆中内存不够继续进行实例分配,且堆也无法再扩展时,将会抛出OutOfMemoryError


    5. 方法区(Method Area)

    方法区和Java堆一样,被所有线程共享

    a. 作用

    用于存储已被虚拟机加载的

    1. 类信息(class metadata)
    2. 常量(包括interned Strings)
    3. 静态变量(类变量 class static variables)
    4. 即时编译器编译后的代码等

    虽然JVM规范把方法区描述为堆的一个逻辑部分,但是它确有一个别名叫Non-Heap,目的应该是与Java堆区分开来

    b. 永久代(HotSpot特有)

    加删除线的原因请看b.2. 现状
    对于使用HotSpot VM的程序员来说,很多人把方法区称之为“永久代(Permanent Generation)”

    为什么叫永久带?如1.4中所说,按内存回收的角度,有新生代、老年代,所以就有了这里的“永久代”。另外,其它虚拟机是没有永久代这个概念的

    本质上两者不等价,仅仅是因为HotSpot团队把GC分代收集扩展到了方法区(或者说用永久代这种方式来实现方法区),这样的话GC就可以像管理Java堆一样管理这部分内存,省去了为方法区编写内存管理代码的工作

    1. 坏处

    如何实现方法区JVM规范并没有强制规定,但是现在看来“永久代”并不是一个好主意

    1. 更容易遇到内存溢出问题
      因为有参数“-XX:MaxPermSize”的上限限制,其它虚拟机只要不达到进程可用内存上限,例如32系统的2GB,就不会出现内存溢出
    2. 有极少数方法(如String.intern()),会因此导致在不同的JVM下有不同表现

    2. 现状

    1. 在JDk1.7的HotSpot中,字符串常量池已经被从永久代中移除了
    2. 在Java8中,根据JEP122,永久带PermanentGeneration已经被从HotSpot中removed.
    3. 这是JDK1.8中JRockit和HotSpot合并的成果
    4. 一篇翻译自国外的译文:Java永久代去哪儿了

    c. 垃圾回收

    JVM规范对方法区限制非常宽松,甚至可以选择不实现垃圾收集

    但并不是如其“永久代”的名字一样,方法区的垃圾回收只是比较少出现。回收目标是:类信息的卸载、常量池的回收

    d. Error

    当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常


    6. 运行时常量池(Run-Time Constant Pool)

    运行时常量池其实是1.5方法区的一部分↑

    class文件中有一项信息是常量池表(constant_pool table),用于存放编译期生成的“字面量”和“符号引用”,这部分内容将在类加载后进入方法区的运行时常量池中(Run-Time Constant Pool)存放

    也就是说:每一个class都会根据constant_pool table 来1:1创建一个此class对应的Run-Time Constant Pool

    a. 作用

    1. 就是运行时所需要的常量数据的容器
    2. JVM规范对class文件的每一部分(包括constant_pool table)都有严格的规范,但是对于运行时常量池却没有做任何细节要求,不过一般来说,除了class文件中的符号引用外,直接引用也会存储在运行时常量池中
    3. 运行时常量池具备动态性,Java语言并没有要求常量一定只能编译期产生,运行期也可以将新常量放入池中。这个特性用的较多的便是String类的intern()方法

    b. Error

    既然运行时常量池是方法区的一部分,自然受到方法区限制,当运行时常量池无法再申请到内存时,将抛出OutOfMemoryError异常

    x. 字符串常量池 - String pool

    注意:这并不是Run-Time Constant Pool的一部分,放在这里只是为了能让大家在比较相似的地方找到

    与上面两个概念不一样,String pool是用来存储被驻留的字符串的(interned string),是JVM实例全局唯一的,被所用类共享

    HotSpot中实现string pool的方式是一个哈希表:StringTable,这个StringTable的value是字符串实例的引用,也就是说某个普通的字符串实例如果被纳入StringTable的引用之后就等同于被赋予了“interned string”的身份

    再有,类的运行时常量池的CONSTANT_STRING类型的常量,经过解析(resolve)后,同样是存字符串的引用,解析的过程中回去查询StringTable,来保证运行时常量池和StingTable所引用的字符串是一致的

    关于字符串部分,请看我的另一篇专门写字符串常量池的博文


    7. 直接内存(Direct Memory)

    直接内存不是JVM规范中定义的内存区域,也不是运行时数据区的内容
    (我现在理解为:直接控制的属于物理机的内存,不属于JVM线程使用的内存)
    但是,这部分内从也被频繁的使用,且可能导致OutOfMemoryError异常,所以罗列为1.7在这里叙述

    a. 缘由

    JDK1.4中加入的NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,这个类可以使用Native函数库直接分配堆外内存,然后通过一个存储在堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场合显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

    b. Error

    直接内存不会受到Java堆大小限制,但是会受到本机总内存大小,以及处理器寻址空间的限制。JVM管理员在配置JVM参数时,会根据本机实际内存设置(如-Xmx等参数),但是经常忽略了要被使用的这一份“直接内存”。最终使得各个内存总和大于物理内存限制,从而导致动态扩展时出现OutOfMemoryError异常



    TIPS

    1. 字面量(literal)

      int a;//a变量
      static final int b=10;//b为常量,10为字面量
      string str=”hello world”;//str为变量,hello world为也字面量
      字面量只能以右值的形式出现

    2. 符号引用

      符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用 项的信息——这些信息必须足以唯一的识别一个类、字段、方法。这样,对于其他类的符号引用必须给出 类的全名。对于其他类的字段,必须给出类名、字段名以及字段描述符。对于其他类的方法的引用必须给出 类名、方法名以及方法的描述符。


    参考文献:

    [ 1 ] 周志明.深入理解Java虚拟机[M].第2版.北京:机械工业出版社,2015.8.
    [ 2 ] Tim Lindholm,Frank Yellin,Gilad Bracha,Alex Buckley.The Java® Virtual Machine Specification . Java SE 8 Edition . 英文版[EB/OL].2015-02-13.
    [ 3 ] James Gosling,Bill Joy,Guy Steele,Gilad Bracha,Alex Buckley.The Java® Language Specification . Java SE 8 Edition . 英文版[EB/OL].2015-02-13.

    展开全文
  • 深入Java核心_Java内存分配原理精讲深入Java核心_Java内存分配原理精讲深入Java核心_Java内存分配原理精讲深入Java核心_Java内存分配原理精讲
  • 深入 Java 核心 Java 内存分配原理精讲 核心提示深入 Java 核心详细介绍一下 Java内存分配方面的知识 Java 内存分配与管理是Java 的核心技术之一今天我们深入Java 核心详细介绍一 下 Java内存分配方面的知识...
  • Java内存分配机制

    千次阅读 2018-08-14 16:49:43
    2 虚拟机就会为其分配内存来存放对象自己的实例变量及其从父类继承过来的实例变量(即使这些从超类继承过来的实例变量有可能被隐藏也会被分配空间)。在为这些实例变量分配内存的同时,这些实例变量也会被赋予默认值...

     

    classLoader 类加载器通过加载class 文件的二进制字码文件在堆中形成java.lang.Class 对象对象

    2 虚拟机就会为其分配内存来存放对象自己的实例变量及其从父类继承过来的实例变量(即使这些从超类继承过来的实例变量有可能被隐藏也会被分配空间)。在为这些实例变量分配内存的同时,这些实例变量也会被赋予默认值(零值)
    3 进行类初始化(实例变量初始化、实例代码块初始化 以及 构造函数初始化。)

    4 进行类的实例化

    Java内存分配机制

    这里所说的内存分配,主要指的是在堆上的分配,一般的,对象的内存分配都是在堆上进行,但现代技术也支持将对象拆成标量类型(标量类型即原子类型,表示单个值,可以是基本类型或String等),然后在栈上分配,在栈上分配的很少见,我们这里不考虑。
     Java内存分配和回收的机制概括的说,就是:分代分配,分代回收。对象将根据存活的时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)。如下图
      这里写图片描述
        
      年轻代(Young Generation):对象被创建时,内存的分配首先发生在年轻代(大对象可以直接 被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快变得不可达,于是被年轻代的GC机制清理掉(IBM的研究表明,98%的对象都是很快消 亡的),这个GC机制被称为Minor GC或叫Young GC。注意,Minor GC并不代表年轻代内存不足,它事实上只表示在Eden区上的GC。

      年轻代上的内存分配是这样的,年轻代可以分为3个区域:Eden区(伊甸园,亚当和夏娃偷吃禁果生娃娃的地方,用来表示内存首次分配的区域,再贴切不过)和两个存活区(Survivor 0 、Survivor 1)。内存分配过程为
      这里写图片描述

    绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快
    当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);
    此后,每次Eden区满了,就执行一次Minor GC,并将剩余的对象都添加到Survivor0;
    当Survivor0也满的时候,将其中仍然活着的对象直接复制到Survivor1,以后Eden区执行Minor GC后,就将剩余的对象添加Survivor1(此时,Survivor0是空白的)。
    当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。
      从上面的过程可以看出,Eden区是连续的空间,且Survivor总有一个为空。经过一次GC和复制,一个Survivor中保存着当前还活 着的对象,而Eden区和另一个Survivor区的内容都不再需要了,可以直接清空,到下一次GC时,两个Survivor的角色再互换。因此,这种方 式分配内存和清理内存的效率都极高,这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中),这不代表着停止复制清理法很高效,其实,它也只在这种情况下高效,如果在老年代采用停止复制,则挺悲剧的。

      在Eden区,HotSpot虚拟机使用了两种技术来加快内存分配。分别是bump-the-pointer和TLAB(Thread- Local Allocation Buffers),这两种技术的做法分别是:由于Eden区是连续的,因此bump-the-pointer技术的核心就是跟踪最后创建的一个对象,在对 象创建时,只需要检查最后一个对象后面是否有足够的内存即可,从而大大加快内存分配速度;而对于TLAB技术是对于多线程而言的,将Eden区分为若干 段,每个线程使用独立的一段,避免相互影响。TLAB结合bump-the-pointer技术,将保证每个线程都使用Eden区的一段,并快速的分配内 存。
      年老代(Old Generation):对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次 Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时, 将执行Major GC,也叫 Full GC。  
      可以使用-XX:+UseAdaptiveSizePolicy开关来控制是否采用动态控制策略,如果动态控制,则动态调整Java堆中各个区域的大小以及进入老年代的年龄。
      如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。用-XX:PretenureSizeThreshold来控制直接升入老年代的对象大小,大于这个值的对象会直接分配在老年代上。
     可能存在年老代对象引用新生代对象的情况,如果需要执行Young GC,则可能需要查询整个老年代以确定是否可以清理回收,这显然是低效的。解决的方法是,年老代中维护一个512 byte的块——”card table“,所有老年代对象引用新生代对象的记录都记录在这里。Young GC时,只要查这里即可,不用再去查全部老年代,因此性能大大提高。

    内存分配:

    初始对象会先在Eden 区上分配,然后如果大对象会直接在老年代上分配

    package javatest.cn.itcast_03_jvm.demo;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.junit.Test;
    
    public class JVMTest {
    	
    	public JVMTest() {
    		//开辟一段内存空间,由于是局部变量在最后的时候是被回收的
    		byte [] m = new byte[20*1024*1024];
    	}
        private Object instance;
        /**
         * -XX:+HeapDumpOnOutOfMemoryError -Xms20m -Xmx20m
         * @param args
         */
        @Test
        public  void testOutOfMemoryError() {
            List demoList =new ArrayList();
            while(true){
                demoList.add(new TestMemory());
            }
        }
        /**
         * 判断对象是否是垃圾:
         * 1 引用计数器
         * -verbose:gc 打印GC日志的简要信息
         * -verbose:gc -XX:+PrintGCDetails
         * -XX:+PrintGCDetails 打印GC日志的详细信息
         */
        @Test
        public  void testJishuqi() {
            JVMTest m1 = new JVMTest();
            JVMTest m2 = new JVMTest();
            //相当于两者相互引用
            m2.instance =m1;
            m1.instance =m2;
            //删除掉两者的地址引用
            m1 =null;
            m2 =null;
            System.gc();//强制进行一次FullGC
        }
        /**
         * PSYoungGen 是使用parallel的标志
         * -verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC 使用SeriesGC
         */
        @Test
        public  void testJVMFenpei() {
        	//新创建的对象是在eden区的,可以看内存看出来
      		byte [] m = new byte[2*1024*1024];
      		byte [] m1= new byte[2*1024*1024];
      		byte [] m2 = new byte[2*1024*1024];
      		byte [] m3= new byte[4*1024*1024];
    //        System.gc();
      		//同样是运行上面的部分主线程和其他线程运行的结果是不一样的
        }
      
    }
    
    import org.junit.Test;
    
    public class NeiCunFenPeiTest {
    	/**
    	 * //同样是运行上面的部分主线程和其他线程运行的结果是不一样的
    	 */
    	public static void main(String[] args) {
    //		byte [] m = new byte[2*1024*1024];
    //  		byte [] m1= new byte[2*1024*1024];
    //  		byte [] m2 = new byte[2*1024*1024];
      		byte [] m3= new byte[7*1024*1024];
      		//通常情况下的垃圾回收是minor GC
      		/*[GC [DefNew: 6981K->484K(9216K), 0.0048746 secs] 6981K->6628K(19456K), 0.0048979 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
      		Heap
      		 def new generation   total 9216K, used 5072K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
      		  eden space 8192K,  56% used [0x00000000f9a00000, 0x00000000f9e7af60, 0x00000000fa200000)
      		  from space 1024K,  47% used [0x00000000fa300000, 0x00000000fa3791e0, 0x00000000fa400000)
      		  to   space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
      		 tenured generation   total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
      		   the space 10240K,  60% used [0x00000000fa400000, 0x00000000faa00030, 0x00000000faa00200, 0x00000000fae00000)
      		 compacting perm gen  total 21248K, used 2553K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
      		   the space 21248K,  12% used [0x00000000fae00000, 0x00000000fb07e6a8, 0x00000000fb07e800, 0x00000000fc2c0000)
      		No shared spaces configured.
      		*/
      		//对于以上日志的解析
    	}
    	/**
         * PSYoungGen 是使用parallel的标志
         * -verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC 使用SeriesGC
         */
        @Test
        public  void testJVMFenpei() {
        	//新创建的对象是在eden区的,可以看内存看出来
      		byte [] m = new byte[2*1024*1024];
      		byte [] m1= new byte[2*1024*1024];
      		byte [] m2 = new byte[2*1024*1024];
      		byte [] m3= new byte[4*1024*1024];
    //        System.gc();
        }
    }
    展开全文
  • java内存分配参数设置

    千次阅读 2019-09-19 13:22:03
    #heap内存 JAVA_OPTS="$JAVA_OPTS -Xmx14336m —最大堆容量 ...-Xms14336m —堆内存初始大小(最大堆容量和初始堆容量大小相等则表示java堆不可扩展) -XX:PermSize=256m —方法区初始容量 ...

    #heap 内存

    JAVA_OPTS="$JAVA_OPTS
    
    -Xmx14336m  —最大堆容量
    
    -Xms14336m  —堆内存初始大小(最大堆容量和初始堆容量大小相等则表示java堆不可扩展)
    
    -XX:PermSize=256m         —方法区初始容量
    
    -XX:MaxPermSize=512m  —最大方法区容量  (可以通过PermSize和MaxPermSize限制方法区大小)
    
    -XX:MaxDirectMemorySize=256m”  — 直接内存(不指定时默认与最大堆容量Xmx一样)
    
            (直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。)
    
    

    nohup java -Xms800m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=2048m -XX:MaxNewSize=512m -jar    xxxx.jar

    转载于:https://my.oschina.net/u/2842177/blog/3094600

    展开全文
  • Java内存分配与管理

    千次阅读 2016-11-24 12:02:50
    Java内存分配与管理是Java的核心技术之一,一般Java在内存分配时会涉及到以下区域: 1.栈区:由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。  2.堆区:由程序员分配...

    Java内存分配与管理是Java的核心技术之一,一般Java在内存分配时会涉及到以下区域:

    1.栈区:由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 
    2.堆区:由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 
    3.全局区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。 
    4.文字常量区:常量字符串就是放在这里的,程序结束后由系统释放 。 
    5.程序代码区 :见名思意:存放代码的区域。


    堆栈内存的分配

    栈区:局部变量存在栈内存中。函数的参数值也存放着栈区。保存类的实例,即堆区对象的引用(指针)。 
    堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。常量池存在于堆内存。 
    代码:package string;

    public class memonry {

    /**
     * @param args
     * a1和a2是局部变量,放在栈区,而new出的对象放在堆区,堆区还有某类的成员变量
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            a a1=new a();
            a1.a=1;
            a1.b="asd";
            a a2=new a();
            a2.a=2;
            a2.b="a2";
    }
    


    class a{ 
    int a; 
    String b; 
    }这里写图片描述

    如果另a2=a1;则图就变成如下所示这里写图片描述
    原因:a2=a1将a1指向堆的地址给了a2,即a2也指向了a1的堆地址。这样原来的那个a2指向的内存就变成Java中所谓的垃圾了,就会被jvm垃圾回收机制所回收。

    static的用法:

    静态static:静态会在堆内存创建一个静态内存区。静态有:静态属性,静态方法,静态类。而静态方法不能调用非静态数据, 
    因为静态属性依赖于类,而不是对象。而非静态依赖于对象,静态类一旦创建,只会有一个,并且在该类中是共享的。一但使用 
    静态属性,那么就会自动赋一个值,比如int型的话默认就为0,boolean的就为false,string就为null。如:某个类中有静态属 
    性时,不应该new一个对象去操作该属性,而是应该直接使用该类名去操作他。 
    使用static的优点: 
    1.一个静态属性在堆内存只能存在一个,即大家可以共享该属性值。 
    2.如果一个对象数组中其中的某人属性大家都是相同的,即可以使用静态,这样可以节省内存空间。 
    3.静态一旦创建,生命周期就会从创建开始到该程序结束才会死亡。 
    4.静态依赖于类,而不是对象。 
    代码: 
    public class Static {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            c.number=12;//通过类名直接更改静态属性,
            c c1=new c();
            //c.number=11;//这样也可以,但会给人错觉,认为是对象去操作该静态类,所以不提倡这种写法。
            c1.a();
            c.b();
            c.c=122;
            c.b();
    }
    


    class c{ 
    public static int c; 
    static boolean a; 
    static int number; 
    String name; 
    public void a(){ 
    System.out.println(number); 
    System.out.println(c);

    }
    public static void b(){
        //System.out.println(name);//因为name为非静态属性,而该方法为静态方法,所以无法调用该属性。
        System.out.println(a);
        System.out.println(c);
    }
    

    }

    展开全文
  • Java 内存分配全面浅析

    万次阅读 多人点赞 2013-02-20 17:54:45
    本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。 进入正题前首先要知道的是Java程序运行在JVM...
  • Java内存分配详解(堆内存、栈内存、常量池)

    万次阅读 多人点赞 2017-10-23 21:04:47
    Java程序是运行在JVM(Java虚拟机)上的,因此Java内存分配是在JVM中进行的,JVM是内存分配的基础和前提。Java程序的运行会涉及以下的内存区域: 1. 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。 2....
  • Java内存分配全面浅析

    万次阅读 多人点赞 2012-06-11 09:46:31
    本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。  进入正题前首先要知道的是Java程序运行在...
  • Java内存划分和分配

    千次阅读 2018-10-18 15:03:41
    综述 在这边文章中我们将了解一下Java的内存区域是怎么...Java内存区域划分 首先通过一张图来看一下Java虚拟机是如何划分内存空间的。 程序计数器:是一块较小内存,可以看作是当前线程所执行的字节码的行号指示...
  • Java基础(三)java内存分配

    千次阅读 多人点赞 2018-03-30 15:54:49
    Java中的内存分配* A:栈(掌握) * 存储局部变量 局部变量:定义在方法声明上和方法中的变量* B:堆(掌握) * 存储new出来的数组或对象 * C:方法区 * 代码 * D:本地方法区 * 和系统相关 * E:寄存器 * 给CPU使用1....
  • Java内存区域划分和内存分配策略

    千次阅读 多人点赞 2020-05-15 12:32:46
    Java内存区域划分和内存分配策略 如果不知道,类的静态变量存储在那? 方法的局部变量存储在那? 赶快收藏 Java内存区域主要可以分为共享内存,堆、方法区和线程私有内存,虚拟机栈、本地方法栈和程序计数器。如下...
  • 深入Java内存分配

    2011-09-29 11:07:52
    Java有几种存储区域? java内存分配 Java内存模型 Java内存分配实例解析 String 常量池问题 堆(Heap)和非堆(Non-heap)内存 堆内存分配 非堆内存分配
  • Java内存分配和管理

    千次阅读 2018-01-14 22:46:13
    Java内存分配时涉及的区域: 寄存器:在程序中无法控制; 栈:存放基本类型的数据和对象的引用,但是对象本身不存放在栈中,而是存放在堆中; 堆:存放用new产生的数据; 静态域:存放在对象中用static定义的...
  • 浅谈Java内存分配策略

    千次阅读 2016-09-11 20:43:51
    Java 内存分配策略 Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。 静态存储区(方法区):...
  • Java深入 - Java 内存分配和回收机制

    万次阅读 多人点赞 2014-06-13 14:55:45
    Java的GC机制是自动进行的,和c语言有些区别需要程序员自己保证内存的使用和回收。
  • java实现内存动态分配

    2016-07-09 08:36:20
    内存动态分配\java实现
  • 再探Java内存分配

    千次阅读 多人点赞 2017-09-01 20:56:54
    我觉得:要回答这个问题不妨先搁置这个问题,先往这个问题的上游走走——Java内存分配。一提到内存分配,我想不少人的脑海里都会浮现一句话:引用放在栈里,对象放在堆里,栈指向堆。嗯哼,这句话听上去没有错;但是...
  • Java 内存分配及容量扩充

    千次阅读 2012-08-02 15:19:39
    一、Java 进程的内存使用 当运行一个Java应用程序时,Java 运行时会创建一个操作系统进程,作为操作系统进程,Java 运行时面临着与其他进程完全相同的内存限制 架构提供的内存寻址能力依赖于处理器的位数,举例来...
  • java 内存分配 final关键字

    千次阅读 2014-02-24 21:50:23
    1. java内存分配 java程序在运行时,内存结构分为:方法区(method),栈内存(stack),堆内存(heap),本地方法栈(java中的jni调用)等。 jvm为每一个运行的线程分配一个堆栈(方法栈),堆栈以帧为...
  • Java内存分配机制(初步整理)

    千次阅读 2017-03-01 08:07:35
    Java程序是运行在Java虚拟机(Java Virtual Machine,JVM)上的,可以把JVM理解为Java程序和操作系统之间的桥梁,JVM实现了Java的跨平台,Java内存分配原理一切都是在JVM中进行的,JVM是内存分配原理的基础与前提。...
  • Java内存管理-内存分配与回收

    千次阅读 2017-12-29 17:48:00
    Java内存管理-内存分配与回收
  • java new 内存分配

    千次阅读 2017-05-16 14:40:41
    在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中...
  • java内存分配机制

    千次阅读 2012-06-14 01:30:44
    通过这几天对一个内存溢出程序的监控,学习了程序运行时对内存的使用机制,在这里和大家分享下。  Java程序运行在JVM(Java ...所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的,JVM是内存
  • java与c++内存分配异同

    千次阅读 2017-09-18 22:50:21
    C++五大内存分区 在C++中,内存分成5个区,他们分别是栈、堆、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的...堆,就是那些由new分配内存块,他们的释放编译器
  • 32、(单选题)在Java语言中,被称为内存分配的运算符是() A.() B.[] C.new D.== 【正确答案】C 【答案解析】Java语言中,程序为对象动态分配内存。Java内存分配的运算符是new。
  • 我的世界如何分配内存

    千次阅读 2021-03-13 23:31:20
    如果你在运行Minecraft时出现内存错误等问题,你可能需要给Minecraft分配更多内存来解决运行故障。如果你玩的是新版本的Minecraft,那么你可以从启动器里直接分配内存(RAM)。如果你使用的是旧版本,那么你需要创建...
  • JVM之---Java内存分配参数(第四篇)

    千次阅读 2013-08-18 13:22:18
    1.内存分配参数---大纲 Ø如何设置堆内存 Ø如何设置栈内存 Ø如何设置方法区 Ø如何设置对的分配比率 Ø设置参数打印堆栈; ØJava程序的两种模式:Server&Client

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 548,120
精华内容 219,248
关键字:

java内存分配

java 订阅
友情链接: Node.rar