• java堆内存和栈内存的处理


    前段时间学习二叉树在处理删除操作的时候遇到一个头疼的问题:删除节点的时候明明已经置null了可树上该节点依旧存在,还必须执行node.father.left = null;才可以删除node节点,寻找了一下原因发现还是因为对java内存管理理解不够深入。

    代码如下:

    	@Test
    	public void testNode() {
    		Node node1 = new Node("node1");
    		Node node2 = new Node("node2");
    		node2.father = node1;
    		node1.next = node2;
    		changeNode(node1.next);
    		System.out.println(node1.next.name);
    	}
    
    	private void changeNode(Node node3) {
    		node3 = null;
    	}
    

      运行代码之后发现本来已经在changeNode()中已经设置node3 = null;可依旧能输出 node1.next.name。

    要知为何?先理解几个概念:

      1、栈内存存储基本类型的变量对象的引用变量。
      2、堆内存用于存放由new创建的对象和数组。每new一个对象就在堆内存中开辟一个新的存储空间存储此实例对象。
      3、Person p = new Person();
        执行new命令时程序执行两步:a:在堆内存中开辟一段空间,存储new出来的对象;b:在栈内存中添加一个变量p,p中存放的是该对象在堆内存中开始存放处的物理地址。
      4、p = null;
        执行此步骤的时候程序只是更改栈内存中的P变量所保存的地址,把地址指向null,而并没有操作堆内存(把p所指向的对象实例清空回收)。
      5、无论是形参或者实参,执行 XXX = null;操作时都是把XXX变量栈中存储的地址改为指向null的地址。不操作堆中的数据。

    下面就分析一下每步代码在堆内存和栈内存中的变化:

      1、当new一个对象的时候,程序首先在堆内存中开辟一段空间实例化对象,同时在在栈内存中加入一个node1的变量,此变量中保存的是堆内存中物理地址的首地址。

      

    2、当调用方法传入参数的时候,在栈内存中添加一个局部变量node3,存储node2的物理首地址。也即是把node2的值0X00011拷贝进node3的栈内存中。

         有网友说这是引用传递,其实传递的还是值,只不过node2的值本来就是物理地址,然后把这个物理地址值传给node3.

    3、当执行node3 = null; 的时候,程序会把node3中的0X00011变为一个指向null的地址 0Xaaaaa.但是程序不对堆内存中数据进行管理(堆内存中没有引用指向的数据会在一定的时间通过GC进行处理)。

    可以看到执行到此步只是把变量中的物理地址置空,但并没有删除node2在堆内存中的数据,这正是为什么删除之后节点之后原数据依旧存在的原因。可以看到node1中的next依旧指向0X00011。

    即使执行node2 = null,程序依旧不改变堆内存。

    原数据依旧存在!

    JVM内存处理实际情况要远远比这复杂得多,如果想深入了解可以找找 jvm内存处理机制相关资料,网上一搜一大堆,不再赘述。其实我也不知道。

      

  • 相关阅读:
    柯西恒等式 FPGA中信号的跨时钟域处理模板(二)
    OSPF
    Windows多网卡路由设置
    使用线程时需要注意的地方
    dicom 影像通信(scu、scp)的c-echo、c-store、c-find、c-move
    关于python3没有numpy和matplotlib库怎么办
    使用centos6.5时的几个小问题
    关于用Apache Beam跑WordCount
    MarkdownPad2的安装、破解和汉化
    安装Photoshop CS64
  • 原文地址:https://www.cnblogs.com/PerkinsZhu/p/5751025.html
Copyright © 2020-2023  润新知