文档章节

常量池、栈、堆的比较

 毛朱
发布于 2017/09/08 16:06
字数 2134
阅读 2
收藏 0
点赞 0
评论 0

http://www.cnblogs.com/Eason-S/p/5658230.html

JAVA中,有六个不同的地方可以存储数据:

1.寄存器:最快的存储区,位于不同于其他存储区的地方——处理器内部。寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。

2. 栈:存放基本类型的变量数据和对象的引用。位于通用RAM中,但通过它的“堆栈指针”可以从处理器哪里获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时候,JAVA编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成 相应的代码,以便上下移动堆栈指针。这一约束限制了程序的灵活性。

3. 堆:一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。  

4. 静态域:存放静态成员(static定义的) 。

5. 常量池:存放字符串常量和基本类型常量(public static final)。 常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。

6. 非RAM存储:硬盘等永久存储空间。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。 

这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。

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

(1)对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

例如:

复制代码

1 String s1 = "china";
2 String s2 = "china";
3 String s3 = "china";
4 String ss1 = new String("china");
5 String ss2 = new String("china");
6 String ss3 = new String("china");

复制代码

对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。

这也就是有道面试题:String s = new String(“xyz”);产生几个对象?答:一个或两个,如果常量池中原来没有”xyz”,就是两个。

 

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

例如:

复制代码

1 int i1 = 9;
2 int i2 = 9;
3 int i3 = 9; 
4 public static final int INT1 = 9;
5 public static final int INT2 = 9;
6 public static final int INT3 = 9;

复制代码

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

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

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

下面给出一个实例:

复制代码

1 class BirthDate {
 2     private int day;
 3     private int month;
 4     private int year;    
 5     public BirthDate(int d, int m, int y) {
 6         day = d; 
 7         month = m; 
 8         year = y;
 9     }
10     省略get,set方法………
11 }
12 
13 public class Test{
14     public static void main(String args[]){
15         int date = 9;
16         Test test = new Test();      
17         test.change(date); 
18         BirthDate d1= new BirthDate(7,7,1970);       
19     }  
20 
21     public void change(int i){
22      i = 1234;
23     }
24 }

复制代码

对于以上这段代码,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()将等待垃圾回收。

 

参考:<http://www.iteye.com/topic/634530>

        <http://www.cnblogs.com/xiohao/p/4296088.html>

        《深入理解java虚拟机———jvm高级特性与最佳实践》

 

JAVA -Xms -Xmx -XX:PermSize -XX:MaxPermSize 区别

JVM按照其存储数据的内容将所需内存分配为堆区与非堆区两个部分:所谓堆区即为通过new的方式创建的对象(类实例)所占用的内存空间;非堆区即为代码、常量、外部访问(如文件访问流所占资源)等。

 

常见参数种类(配置内存):(-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn)、(-XX:PermSize、-XX:MaxPermSize)。可以从列举的方式上看出我的用意,参数的配置是分组的,前者是用来配置堆区的,后者是用来配置非堆区的。
    第一组配置参数:-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn

    
    1、-Xms :表示java虚拟机堆区内存初始内存分配的大小,通常为操作系统可用内存的1/64大小即可,但仍需按照实际情况进行分配。有可能真的按照这样的一个规则分配时,设计出的软件还没有能够运行得起来就挂了。
    2、-Xmx: 表示java虚拟机堆区内存可被分配的最大上限,通常为操作系统可用内存的1/4大小。但是开发过程中,通常会将 -Xms 与 -Xmx两个参数的配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。

接下来要讲述的三个参数是用来控制新生代内存大小的。

    1、-XX:newSize:表示新生代初始内存的大小,应该小于 -Xms的值;
    2、-XX:MaxnewSize:表示新生代可被分配的内存的最大上限;当然这个值应该小于 -Xmx的值;
    3、-Xmn:至于这个参数则是对 -XX:newSize、-XX:MaxnewSize两个参数的同时配置,也就是说如果通过-Xmn来配置新生代的内存大小,那么-XX:newSize = -XX:MaxnewSize = -Xmn,虽然会很方便,但需要注意的是这个参数是在JDK1.4版本以后才使用的。

 

上面所述即为java虚拟机对外提供的可配置堆区的参数,接下来讲述java虚拟机对非堆区内存配置的两个参数:

    1、-XX:PermSize:表示非堆区初始内存分配大小,其缩写为permanent size(持久化内存)
    2、-XX:MaxPermSize:表示对非堆区分配的内存的最大上限。

本文转载自:

共有 人打赏支持
粉丝 19
博文 147
码字总数 170387
作品 0
济南
String常见题分析

例1 1.1 代码 package com.ilaoda.day0903; /** 字符串的常见题1 @author iLaoda **/public class Test1 { public static void main(String[] args) {String s1 = "hello";String s2 = "wor......

Hu_Captain ⋅ 2015/09/03 ⋅ 0

堆 栈 常量池

a.在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自...

王大豆 ⋅ 2015/08/09 ⋅ 0

深度解析Java内存的原型

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

紫宸 ⋅ 2013/01/23 ⋅ 0

jvm内存原型剖析

一、java虚拟机内存原型 寄存器:我们在程序中无法控制栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中堆:存放用new产生的数据静态域:存放在对象中用static定...

刘学炜 ⋅ 2012/07/04 ⋅ 0

java虚拟机内存解析

一、java虚拟机内存原型 寄存器:我们在程序中无法控制栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中堆:存放用new产生的数据静态域:存放在对象中用static定...

lvzjane ⋅ 2012/12/25 ⋅ 0

JAVA中堆栈和内存分配

(一)、栈、堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的...

mahout ⋅ 2012/03/25 ⋅ 0

JVM之Java内存区域与内存溢出异常

Java的JVM可以自动管理内存,包括内存动态分配和垃圾收集等。 简介 JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间...

Jeffbond ⋅ 2017/04/08 ⋅ 0

JVM虚拟机的内部结构

Java虚拟机的内部体系结构也许很少有人去关心,因为对于Java程序员来说,一般只需要跟API打交道就可以了。这些体系结构只是Java虚拟机内部的结构而已。但是如果理解了其内部结构,对于我们开...

五大三粗 ⋅ 2015/05/20 ⋅ 0

Java 内存分配全面浅析

本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。 进入正题前首先要知道...

vieky ⋅ 2014/12/10 ⋅ 3

Java内存分配全面浅析

本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。 进入正题前首先要知道...

浮躁的码农 ⋅ 2016/04/19 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring表达式语言(SpEL)

1、SpEL引用 Spring EL在bean创建时执行其中的表达式。此外,所有的Spring表达式都可以通过XML或注解的方式实现。下面将使用Spring表达式语言(SpEL),注入字符串,整数,Bean到属性。 SpEL的...

霍淇滨 ⋅ 26分钟前 ⋅ 0

Gradle使用阿里云镜像

gradle 生命周期中有一个初始化( Initialization )的过程,这个过程运行在 build script 之前,我们可以在这个地方做一点系统全局的设置,如配置仓库地址。 你可以在以下几个位置实现仓库地址...

明MikeWoo ⋅ 34分钟前 ⋅ 0

appium+python3.6

1.安装jdk1.8(不知道为啥只识别1.8,1.10不识别,所以为了少折腾,迁就安装1.8) http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 配置 JAVA_HOME:...

Kampfer ⋅ 53分钟前 ⋅ 0

详解Apache 日志分割教程

一、日志切割 安装cronolog CentOS 5.3中编译安装Apache日志默认是不切割的,需要用用工具Cronnolog进行日志切割。 1.下载及安装 wget http://cronolog.org/download/cronolog-1.6.2.tar.gz ...

dragon_tech ⋅ 55分钟前 ⋅ 0

Keepalived介绍

负载均衡器(Load Balancer, LB )是一组能够将IP数据流以负载均衡形式转发到多台物理服务器的集成软件。有硬件负载均衡器和软件负载均衡器之分,硬件负载均衡器主要是在访问网络和服务器之间...

寰宇01 ⋅ 55分钟前 ⋅ 0

java8-Collections and Streams

stream和集合的区别是什么? 1.在计算的时候处理不同, 2.every element should be computed in the memory and then to be part of collections stream Stream apis filter with a predica......

writeademo ⋅ 今天 ⋅ 0

Confluence 6 重新获得附件指南

每一个文件在恢复上传到 Confluence 的时候必须单独重命名,你可以通过下面说明的 3 个方法中选择一个进行操作: 选择 A - 通过文件名恢复附件 如果你知道你需要恢复的每一个文件名,尤其是你...

honeymose ⋅ 今天 ⋅ 0

【每天一个JQuery特效】根据状态确定是否滑入或滑出被选元素

主要效果: 本文主要采用slideToggle()方法实现以一行代码同时实现以展开或收缩的方式显示或隐藏被选元素。 主要代码如下: <!DOCTYPE html><html><head><meta charset="UTF-8">...

Rhymo-Wu ⋅ 今天 ⋅ 0

度量.net framework 迁移到.net core的工作量

把现有的.net framework程序迁移到.net core上,是一个非常复杂的工作,特别是一些API在两个平台上还不能同时支持。两个类库的差异性,通过人工很难识别全。好在微软的工程师们考虑到了我们顾...

李朝强 ⋅ 今天 ⋅ 0

请不要在“微服务”的狂热中迷失自我!

微服务在过去几年一直是一个非常热门的话题(附录1)。何为“微服务的疯狂”,举个例子: 众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常...

harries ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部