浅谈java内存堆栈

浅谈java内存

最近看安卓完全没有头绪了,开始回顾回顾java
首先进去正题,java程序是运行在java虚拟机上的,就是因为JVM的
存在java才可以如此多平台使用

简单的讲,一个完整的java程序运行过程会涉及一下内存区域
寄存器: JVM内部虚拟寄存器,存取速度非常快
: 保存局部变量的值,和 引用对象,引用变量。1,保存基本数据类型的值;2.保存对象的引用对象即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。
: 用来存放动态产生的数据,比如new 出来的对象。对象的引用在栈里面,实际对象储存在堆内,注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
常量池 : 首先说一下,常量池和对象内存都在存放在堆内存中的。JVM为每个已经加载的类维护一个常量池,注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。
以下是内存图

仔细说说怎么说呢?
* 1.一个java程序他主要的入口就是main方法,只要有main方法java程序就可以运行
* 2.无论是普通类型的变量还是引用类型的变量,都可以作为局部变量,都可以出现在栈中,他们都可以出现在栈中。只不过普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此,普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。
* 下面是烦博客翻倒一个不错的案例来帮助理解 有些说的不清楚的我加了

1 首先jVM是会先去寻找Main方法这个程序入口的,然后创建一个Test类的实例。在栈中分配一块内存存放一个指向堆区对象的引用变量(指针110925),不得不说java中也有指针不过包装起来了。 所以引用变量中存放的还是堆内存中对象的地址 **
2 创建一个 int 类型变量data 由于它是基本类型,所以直接储存在栈中 对应的值为9 **
3 创建两个BirthDate类的实例d1、d2,在栈中分别存放了对应的指针指向各自的对象。他们在实例化时调用了有参数的构造方法,因此对象中有自定义初始值。 **

调用test对象的change1方法,并且以date为参数。JVM读到这段代码时,检测到i是局部变量,因此会把i放在栈中,并且把date的值赋给i。



这里解释一下,抽闲的d1以一个参数的形式传递进去了changer2方法所以现在栈中的引用b 和引用 b1 指向的是同一个对象。在b和d1之间传递是指针。和堆中的对象无关

这里在说一下 关于栈中的引用指向堆中的内存,首先他先会按堆中有没有如果有直接指向它,如果没有新建一个在指向它
这里b 这个引用就完成了这个步骤,需要注意的是 此时实例b不再指向实例d1所指向的对象,但是实例d1所指向的对象并无变化,这样无法对d1造成任何影响。



然后就是 当b调用setDay方法时候堆中的内存也会改变,也就是d2所指向的的堆对象也会改名,可以理解成他们就是堆对象的两个不同名字罢了,然后让方法结束,栈会自动出栈b
以上就是Java程序运行时内存分配的大致情况。其实也没什么,掌握了思想就很简单了。无非就是两种类型的变量:基本类型和引用类型。二者作为局部变量,都放在栈中,基本类型直接在栈中保存值,引用类型只保存一个指向堆区的指针,真正的对象在堆里。作为参数时基本类型就直接传值,引用类型传指针(在java中只有值传递没有地址传递但是引用变量中存放的是堆中对象的地址,所以也可以理解为地址传递)。

最后

小结:

1.分清什么是对象引用变量(引用变量)什么是对象。Class a= new Class();此时a叫对象引用变量,而不能说a是对象。引用变量在栈中,对象在堆中,操作引用变量实际上是通过引用间接操作对象。多个引用变量可以引用到同一个对象。

2.栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。

3.每个方法执行的时候都会建立自己的栈区,在方法中定义的局部变量(参数,方法中定义的变量)都在栈区中存放当方法结束时这些局部变量也就结束了,但是堆内存中的对象不会随着方法的结束而销毁而是判断还有没有引用变量引用到这个对象如果有的话就是说这个对象可达所以不会轻易的被GC回收,如果这个对象没有被引用如果这时垃圾回收系统开始回收但发现这个对象没有引用的话就会调用finalize()方法来判断这个对象是否可以再次可达如果可以的不会回收但是不过不可达的话可能会被回收(不是一定会被回收这里是不一定会回收因为这里还有对象的引用类型如:强引用,软引用(softReference来实现),弱引用(WeakReference来实现)等因素有关,还要考虑其他的因素不在这里一一说明)如果可达的话还是不会回收的。

4.以上的栈、堆、代码段、数据段等等都是相对于应用程序而言的。每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响,调用JVM也就是激活一个进程。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。

5.类中定义的实例成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类中定义的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。

以上分析只涉及了栈和堆,还有一个非常重要的内存区域:常量池,这个地方往往出现一些莫名其妙的问题。常量池是干嘛的上边已经说明了,也没必要理解多么深刻,只要记住它维护了一个已加载类的常量就可以了。接下来结合一些例子说明常量池的特性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值