Android必须知道的Java内存结构及堆栈区别

一、认识Android储存结构


对于Android来说,存储主要分为三个部分:内存、内部存储以及外部存储,详细介绍如下:

(1)内存存储RAM(Random Access Memory)
内存与PC的内存是一样的,是用来运行程序,不能用来永久存储数据,手机一旦关机,在内存中的所有数据都将会丢失,内存也是现在人类制造的所有电子设备所必需拥有的。

(2)内部存储ROM(Read Only Memory)
就是就相当于是PC中的硬盘的角色。用于存储Andoid 设备的操作系统和应用程序的存储介质。也就是说,Android设备中的Android系统和应用程序(APK文件)都是存在内部存储区的。例如手机的/system/目录、/data/目录等。

(3)外部存储区
相当于PC中的U盘或者移动硬盘。

由于Android设备通常会将内部存储器芯片固定在芯片上,所以一般无法更换内部存储器的。 为了增强Android设备的存储能力,很多Android设备都支持扩展的SD卡功能(通常称之为MicroSD类型的存储卡)。所以我们经常说的3GB+32GB或者 3GB+64GB是指 内存是3GB大小、内部存储大小为32GB或者64GB大小。

二、 Java内存结构


1、栈区(stack),由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap),一般由程序员分配释放, 若程序员不释放,JVM不定时观察发现没有引用指向时会GC回收 。
3、静态区(static storage),存放由static修饰的静态成员。 程序结束后由系统释放。
4、常量区(constant storage),基础类型、字符串等就是放在这里的。常量存储位于堆中。程序结束后由系统释放 。
5、代码区,存放函数体的二进制代码,而且是多个对象共享代码空间区域。


基本数据类型存在栈(stack), 引用数据类型存在堆(heap)。java数据类型结构图:

                                             ┏数值型━┳━整数型:byte short int long
              ┏基本数据类型━━┫                ┗━浮点型:float double
              ┃                            ┣字符型:char                                          

数据类型  ╋                            ┗布尔型:boolean              

              ┃                            ┏类(class)
              ┗引用数据类型━━╋接口(interface)
                                             ┗数组(array)


基本数据类型和引用数据类型的区别:

(1)从概念方面来说:
    基本数据类型:变量名指向具体的数值;
    引用数据类型:变量名指向存数据对象的内存地址,即变量名指向hash值。

(2)内存构建方面来说:
    基本数据类型:变量在声明之后java就会立刻分配给他内存空间;
    引用数据类型:这类变量声明时不会分配内存,只是存储了一个内存地址。

(3)从使用方面来说:
    基本数据类型:使用时需要赋具体值,判断时使用“==”号;
    引用数据类型:使用时可以赋null,判断时使用equals方法。


(4)从局部声明来说:(即局部变量)

    基本数据类型:所声明的变量名及值都是放在方法栈中;

    引用数据类型:所声明的变量(内存地址值)是放在方法的栈中,该变量所指向的对象实际是放在堆内存中。


(5)从全局声明来说:(即全局变量)

    基本数据类型:所声明的变量名及其值放在堆内存中;

    引用数据类型:所声明的变量(内存地址值)指向所引用的对象。该变量名和对象都存储在相应的堆内存中。


三、 堆和栈的区别


    栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
     Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、new array、anewarray和 multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
     Java的栈存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄。栈有一个很重要的特殊性,就是存在栈中的数据可以共享。例如:
int a = 3;
int b = 3;
    编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况,就可以使用 == 进行比较。另外,a的值改变并不影响到b的值,如果令a = 4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将 a 指向这个地址即可。

(为了更好理解各大区分配关系,专门配上了图示和小案例)


听说理解上,小案例跟图示更配哦:
public class Test {
	String a = "123456";    //值在常量池中
        String b = "123456";   // a == b true 引用地址相同。因为值在常量池中已存在,所以两个变量指向的是同一个对象。
	final int A = 0; 		//final常量,堆中
	String[] c=new String[5]; 		// 手动分配new创建对象,在堆中
        static int d =0; 		//静态区
	public static void main(String args[]) () {//方法栈
	        a = new String("123"); //创建了两个String对象,一个存于常量池中,一个于堆内存中且由a指向。

                b = new String("123");//创建一个对象在堆内存中由b指向。因为常量池中已经存在"123"对象。

		String c = "123"; 	//值“123”在常量池堆中已存在。变量
	}
}

例如:String a = "123456";  // 引用对象 a  ,值 123456 在常量池中。为什么呢?

    因为,基本数据类型存在栈(stack), String的对象实例存在堆(heap)。基础数据类型在栈里面直接分配内存 ,而引用数据则是通过堆里的对象来对栈中的内容进行引用。在 java 中 String 是个对象,是引用类型不是基本数据类型,判断是否相等,不能使用==,而使用equals方法。java中对 String 对象特殊对待,在堆区域给分成了两块,一块是 String constant pool(存储java字符串常量对象),另一块用于存储普通对象及字符串对象。另外,java虚拟机处理基础类型与引用类型的方式是不一样的,对于基本类型,java虚拟机会为其分配数据类型实际占用的内存空间;而对于引用类型变量,它仅仅是一个指向堆区中某个实例的指针。

字符串在内存中的存储情况如下所示:

String s1 = "abc";    
String s2 = "xyz";    
String s3 = "123";    
String s4 = "A";    
String s5 = newString("abc");     
char[] c = {'J','A','V','A'};     
String s6 = newString(c);      
String s7 = newString(newStringBuffer());  


推荐阅读:

Java Final修饰符存储位置,为什么String是不可变的?


本人研究不深,若有错误请指正。

———————————————————————————结尾———————————————————————————


  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java内存结构主要可以分为以下几个部分: 1. (Heap):用于存储对象实例,是Java程序中最大的一块内存空间,可通过“new”关键字创建对象时,将对象存储在上。 2. (Stack):用于存储局部变量和方法调用,每个线程都会创建一个中的数据是线程私有的,只有当前线程可以访问。 3. 方法区(Method Area):用于存储类信息、常量、静态变量和即时编译器编译后的代码等数据,是各个线程共享的内存区域。 4. 本地方法(Native Method Stack):用于存储Java调用本地方法时的参数和返回值,以及本地方法的调用和返回状态。 Java程序中最基本的内存结构是用来存储对象实例的,它是Java程序中最大的一块内存空间。内存是由JVM管理的,可以通过“new”关键字创建对象时,将对象存储在上。内存的大小可以通过JVM参数进行配置,如果内存不足,会抛出OutOfMemoryError异常。 是用来存储局部变量和方法调用的,每个线程都会创建一个中的数据是线程私有的,只有当前线程可以访问。内存是由操作系统管理的,它的大小是有限制的,如果内存不足,会抛出StackOverflowError异常。 在方法调用时,JVM会为每个方法调用创建一个帧,帧包含了局部变量表、操作数、动态链接、方法返回地址等信息。当方法调用结束时,这个帧会被弹出。 总之,Java程序中最基本的内存结构用于存储对象实例,用于存储局部变量和方法调用。它们的使用方式和内存管理方式都有所不同,程序员需要根据具体情况来选择合适的数据结构内存管理策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾阳Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值