说到Java中堆、栈和常量池,首先还是看看他们各自存放的数据类型吧!

栈:

Java的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)也叫静态存储区。

堆区:(存放所有new出来的对象;)

1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)

2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

栈区:(存放基本类型的变量数据和对象的应用,对象(new出来的对象)本身并不存在栈中,而是存放在堆中或者常量池中(字符串常量对象存放在常量池中))

1.每个线程包含一个栈区,栈中只保存基础数据类型的对象(比如int i=1中1就是基础类型的对象)和自定义对象的引用(不是对象)而真实对象都存放在堆区中

2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。

3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

常量池:存放基本类型常量和字符串常量。

方法区:

1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量名,不是常量(它在堆栈中)。

进一步解析:

(指数据共享时)对于栈和常量池中的数据可以共享(具有多个引用对象),对于堆中的对象不可以共享(一个引用对象)。         (指线程共享时)比如:同一个进程的多个线程堆栈共享状况哪个描述正确?线程共享堆,但是每个线程有自己的寄存器和栈

解析:    线程占有的都是不共享的,其中包括:栈、寄存器、状态、程序计数器

线程间共享的有:堆,全局变量,静态变量,主要指共享进程的资源;

进程占有的资源有:地址空间,全局变量,打开的文件,子进程,信号量、账户信息。

栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

而对于字符串来说,其对象的引用都是存储在栈中的,如果是编译期已经创建好(即指用双引号定义的)的就存储在常量池中,如果是运行期(new出来的对象)则存储在堆中。对于equals相等的字符串,在常量池中是只有一份的,在堆中则有多份。

关于:方法区理解

在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。

因为方法区是被所有线程共享的,所以必须考虑数据的线程安全。假如两个线程都在试图找lava的类,在lava类还没有被加载的情况下,只应该有一个线程去加载,而另一个线程等待。方法区的大小不必是固定的,jvm可以根据应用的需要动态调整。同样方法区也不必是连续的。方法区可以在堆(甚至是虚拟机自己的堆)中分配。jvm可以允许用户和程序指定方法区的初始大小,最小和最大尺寸。方法区同样存在垃圾收集,因为通过用户定义的类加载器可以动态扩展Java程序,一些类也会成为垃圾。jvm可以回收一个未被引用的(没有实例对象)类所占的空间,以使方法区的空间最小。

方法区存在类成员表的理解

Java方法调用面临两个新的问题是方法重载和方法重写,方法重载使用的技术叫符号毁坏,方法重写的技术叫做动态派发。Java中的所有方法都支持重写,要实现在运行时动态确定调用的具体方法就需要一张方法表,这张方法表记录当前对象所对应的类含有的所有方法包括父类的方法。方法调用的时候需要从子类方法开始搜索这张表,如果子类未找到就到父类找,再父类。。。;符号毁坏沿用了C++的解决方法,就是给方法重命名如method+参数个数(args) 这样方法就唯一了。所以核心问题还是方法重写,也就是动态派发,也是java的性能瓶颈,因为C++只有virtual方法才会产生动态派发。

要处理好动态派发,一种可能的实现方式是专门开辟一个区,单独管理所有方法,可以按照稳定性对于该对象的所有方法(当然包括父类方法)进行稳定性排序,使相同方法聚集在一起。当方法调用时在方法区搜索的时候一次定位到相同方法的位置的起始处,不管第一个命中方法是父类还是子类,也不管此处相同方法的个数,始终执行第一个。

作者:寻寒

链接:https://www.zhihu.com/question/23599282/answer/25076568

来源:知乎

著作权归作者所有,转载请联系作者获得授权。

举个例子吧!

Java代码

String s1 = "china";

String s2 = "china";

String s3 = "china";

String ss1 = new String("china");

String ss2 = new String("china");

String ss3 = new String("china");

对于基础类型的变量和常量:变量和引用存储在栈中,常量存储在常量池中。

如以下代码:

Java代码

int i1 = 9;

int i2 = 9;

int i3 = 9;

public static final int INT1 = 9;

public static final int INT2 = 9;

public static final int INT3 = 9;

对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。

形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。

成员变量存储在堆中的对象里面,由垃圾回收器负责回收。

如以下代码:

Java代码

class BirthDate {

private int day;

private int month;

private int year;

public BirthDate(int d, int m, int y) {

day = d;

month = m;

year = y;

}

省略get,set方法………

}

public class Test{

public static void main(String args[]){

int date = 9;

Test test = new Test();

test.change(date);

BirthDate d1= new BirthDate(7,7,1970);

}

public void change1(int i){

i = 1234;

}

对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:

1. main方法开始执行:int date = 9;

date局部变量,基础类型,引用和值都存在栈中。

2. Test test = new Test();

test为对象引用,存在栈中,对象(new Test())存在堆中。

3. test.change(date);

i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。

4. BirthDate d1= new BirthDate(7,7,1970);

d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。 day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。

5.main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(),new BirthDate()将等待垃圾回收。

java 常量区存放 new_java---堆、栈、常量池的存储数据相关推荐

  1. java 常量区存放 new_java常量池与对象存储

    一 数据存储位置 我们先来谈谈数据的存储位置,有五个地方可以存储数据 (1)寄存器:这是最快的存储区,因为它位于不同于其他存储区的地方-处理器内部.对于程序员来说是透明的不能直接控制,并且数量有限. ...

  2. java静态变量存放在堆还是方法区?

    首先肯定:静态变量是被对象共享的,随着类加载而产生(不用实例化即可访问) jdk8之前:放在方法区 jdk8及以后:存放在堆中反射的class对象(即类加载后会在堆中生成一个对应的class对象)的尾 ...

  3. java 反射 静态域_java 内存 堆 栈

    本文主要通过分析Java内存分配的栈.堆以以及常量池详细的讲解了其的工作原理. 一.Java虚拟机内存原型 寄存器:我们在程序中无法控制 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而 ...

  4. JVM Runtime Data Area(运行时数据区中的堆/栈/方法区讲解)

    JVM的组成 JVM由4大部分组成:ClassLoader .Runtime Data Area .Execution Engine .Native Interface.我们这里重点讲得是Runtim ...

  5. bss,data,text,rodata,堆,栈,常量段

    //红色部分为问题部分 section 结构 SECTIONS { ... secname start BLOCK(align) (NOLOAD) : AT ( ldadr )   { content ...

  6. linux代码段映射,bss,data,text,rodata,堆,栈,常量段与其各段在物理存储中关系

    本文想从linux出发[目前还想可不可以从51单片机出发],解答程序代码和各种数据结构是如何存储(映射)到存储区的. 目前未完成整理,还是初稿的想法.bss段: BSS段(bsssegment)通常是 ...

  7. JAVA 方法区是在堆里面吗

    三种情况: 1. java7之前,方法区位于永久代(PermGen),永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值,不可变: 2. java7中,static变量从永久代移到堆中: ...

  8. Java中栈、堆和常量池

    2019独角兽企业重金招聘Python工程师标准>>> Java内存分配主要包括以下几个区域: 寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.. 栈 存放基 ...

  9. c语言中全局变量内存,C语言——全局变量和局部变量在内存中的区别——及编译后的内存分区【栈-堆-全局存储区-文字常量区-程序代码区】...

    目录: 一:全局变量 二:局部变量 三:C语言经过编译之后将内存分为以下几个区域 (1)栈(stack) (2)堆(heap) (3)全局(静态)存储区 (4)文字常量区 (5)程序代码区 四:区别 ...

最新文章

  1. 流行于机器学习竞赛的Boosting,这篇文章讲的非常全了
  2. 键盘工具栏的快速集成--IQKeyboardManager
  3. axure 鼠标样式,Axure8-动态面板+简单鼠标事件实现单页面应用
  4. JAVA开发面试常问问题总结2
  5. 本科毕业找不到工作,是怎样的体会
  6. expect免互交 常用编辑文本
  7. 设计模式---组件协作模式之观察者模式(Observer)
  8. amoeba主从复制
  9. VMWare 导出vmdk并转为qcow2格式
  10. PDF文件格式转换工具 迅捷PDF转换成Word转换器
  11. 新安装Windows 2012 启动报错0xc0000225
  12. 从东京奥运会看js设计模式之发布订阅模式
  13. 亚航app航班价格抓取
  14. JAVA 页面置换先进先出算法(FIFO)
  15. 百度,互联网的“流氓大亨”?
  16. Dialer中界面组成、Call对象和log分析
  17. 用于生成随机数的python标准库模块是_详解Python基础random模块随机数的生成
  18. windows USB读卡器驱动详解
  19. php屏蔽手机号码,PHP正则表达式屏蔽电话号码中间段
  20. 华为云桌面服务器地址怎么看,探索华为FusionAccess云桌面的真面目

热门文章

  1. IDE 插件新版本发布,开发效率 “biu” 起来了
  2. 阿里云全球首推流量型独享虚拟主机新规格,网络访问速度最高提升400%
  3. Multi Task Learning在工业界如何更胜一筹
  4. PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程)
  5. 低代码发展专访系列之一:低代码平台产品的使用者都是谁?
  6. 一行代码,揭开 CPU 执行原理!
  7. 智能可穿戴迎来长续航焕新活力 出门问问TicWatch Pro 3即将国内上市
  8. 如何选择基于 Kubernetes 的 PaaS?
  9. 腾讯首度披露基础架构演进史:“海量之道”进化“生而为云”
  10. 5G精华问答 | 5G的关键无线技术是啥?