JVM 变量存储位置

7 篇文章 1 订阅

1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:方法执行时创建方法栈帧,存放基本类型的变量数据和对象的引用,还有未逃逸的小对象标量替换存储。(未逃逸=作用域只在方法栈帧中)
3. 堆:存放所有new出来的对象。
4. 静态域(方法区):存放静态成员(static定义的)
5. 常量池(方法区):存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储:硬盘等永久存储空间

方法区:

1.7:类信息、常量池、静态变量、即时编译器编译后的代码等数据,存储在 Perm(永久带)。

1.8:常量池和静态变量放到了Java堆,类元数据放到了本地直接内存MetaSpace。

这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
如以下代码:

String s1 = "china";  
String s2 = "china";  
String s3 = "china";  
String ss1 = new String("china");  
String ss2 = new String("china");  
String ss3 = new String("china"); 

 

这里解释一下黄色这3个箭头,对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。这也就是有道面试题:String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。

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

如以下代码:

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; 

对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。
形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。
成员变量存储在堆中的对象里面,由垃圾回收器负责回收。

如以下代码:

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()将等待垃圾回收。

 

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
1.redis支持的数据结构 string list hash set zset(基本回答) 加分项:另外redis还对这几种数据结构做了扩展,如GEO对位置计算,hyperLogLog做统计,bitmaps:redis底层存储value值都是存储的二进制数据,redis提供bitmaps(位图)可以直接访问或修改底层存储的二进制数据 2.redis线程模型 redis是单线程实现。 3.redis 提供的持久机制 redis 支持rdb和aof两种持久机制,redis4.0后支持混合持久化。rdb是定时的持久机制,宕机有可能会丢失最后一次持久化之后存在数据丢失。aof是基于操作日志追加的持久机制。(基本回答) 加分项: 1.rdb持久化原理 原理是redis会单独创建(fork)一个与当前进程一模一样的子进程来进行持久化, 这个子线程的所有数据(变量。环境变量,程序程序计数器等)都和原进程一模一样,会先将数据写入到一个临时文件中, 待持久化结束了,再用这个临时文件替换上次持久化好的文件 2.他什么时候fork子进程,或者什么时候触发rdb持久化机制 shutdown时,如果没有开启aof,会触发 配置文件中默认的快照配置 执行命令save或者bgsave save是只管保存,其他不管,全部阻塞 bgsave: redis会在后台异步进行快照操作,同时可以响应客户端的请求,但是在调用fork函数时是阻塞的,很快,可以忽略不计 执行flushall命令 但是里面是空的,无意义 3.aof原理? 原理是将Reids的操作日志以追加的方式写入文件,读操作是不记录的 2.触发机制(根据配置文件配置项) no:表示等操作系统进行数据缓存同步到磁盘(快,持久化没保证) always:同步持久化,每次发生数据变更时,立即记录到磁盘(慢,安全) everysec:表示每秒同步一次(默认值,很快,但可能会丢失一秒以内的数据) 以下问题都是基本回答: 4.redis支持事务吗 redis可以说是半支持事务(假事务),提供了一些在一定程度上支持线程安全和事务的命令。例如:multi/exec watch inc等。但是redis的事务并不支持回滚,即可以两个命令可以同时提交执行,但是如果有失败,成功的也不会回滚 5.你们公司使用的是什么集群模式 看你写的项目经验,如果你们公司数据量特别大,公司用缓存牛逼,就说Rediscluster,小公司可以说哨兵集群 1.哨兵模式 基本回答:哨兵主要就是启动哨兵(redis特殊)节点,对主节点进行监控,如果半数以上发现ping主节点不通了,认为主节点挂了,则进行故障转移,就是选出一个从节点代替主节点 2.Rediscluster集群模式 基本回答:Rediscluster是一个高可用集群,它基于分片(对key进行crc16,然后对16384取余)的原理,可以把他理解为是由多组哨兵集群组成,但是它不依赖哨兵 6.缓存穿透 缓存穿透指的是使用不存在的key进行大量的高并发查询,这导致缓存无法命中,每次请求都要穿透到后端数据库系统进行查询,数据库压力过大。 常用解决方案:将空值缓存起来。 其他解决方案:使用布隆过滤器(guava 19开始已支持布隆过滤器) 备注:如果你可以理解太白老师讲的基于redis位图自己实现的布隆过滤器,可以说说,更加分 7.缓存击穿 缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力 解决方案:1.互斥锁 如果项目不会多部署则可以使用jvm锁,如果会多部署则使用分布式锁 8.缓存雪崩 缓存雪崩指缓存服务器重启或者大量缓存集中在某一个时间段内失效 常用解决办法: 1.主要就是要搭建高可用集群,保证机器的高可用。 2.对不同的数据使用不同的失效时间,甚至对相同的数据、不同的请求使用不同的失效时间。
java概述 计算机能识别的语言: 1.机器语言:由0和1组成可以被电脑理解。 2.汇编语言:由汇编软件把汇编语言翻译成机器语言 3.高级语言:由高级语言的编译器来把高级语言翻译成机器语言,然后计算机来运行。如:java,c,c++。 java语言的特点: 1.简介有效:面向对象。 2.java跨平台:一次编译处处运行。java为每一个平台提供jvm(java virtual machine) 3.适合分布式项目:java语言具有强大的,易于使用的互联网能力,非常适合大型的互联网分布式项目。   java分支: 1.javase(标准版) 2.javame(微型版),给移动设备做支持,基本淘汰了 3.javaee(企业版) JRE和JDK概述和软件安装 JRE(java runtime environment) java运行环境。 JVM(java virtual machine     java虚拟机):java程序会载入JVM,然后运行。 java核心类库:java程序在运行的过程中需要依赖一些库文件。 JDK(java development kit)  java开发工具。 JDK包含JRE,我们直接安装JDK就可以了。   安装JDK 从oracle官网下载对应的JDK安装包(不要安装到中文目录,最好安装到c盘)。     JDK是通过命令行来使用的。   JDK目录 bin目录(binary  二元的)二进制文件或可执行文件: java.exe:运行 javac.exe:编译   db目录(关于数据的存储)   include目录(本地接口编程): 包含C语言给java语言提供的一些接口支持   jre目录:java运行环境   lib目录:java开发工具包   zip文件是jdk里面的源码 jdk环境变量配置 环境变量 电脑右键属性——高级系统设置——高级——环境变量             path项:dos窗口下输入的命令会先当前目录下查找命令。若没有,会在path项里的目录下查找命令是否存在。 当需要运行某些程序命令时会先在当前文件夹中寻找,如果当前目录下找不到,就会到设置的默认路径中去查找,如果发现在默认路径中找到程序的位置,就直接运行,这样就实现程序命令随叫随到。这个“默认路径”就是环境变量。 内部命令指的是当前目录下存在的命令。 外部命令指的是path目录下存在的命令。 jdk的环境变量配置: 1.配置JAVA_HOME:在环境变量中系统变量里新建一项: 2.在Path中添加如下目录 +     classpath的配置 classpath是我们类存放的根路径,我们可以设置classpath来在任意路径来执行java的class类 .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(.   代表当前路径) java运行机制、java标识符 java标识符 1.在java语言中,对各种变量,方法和类等要素命名时所使用的字符序列就是标识符。 有些标识符是jdk定义好的(关键字。 如:public) 2.java中标识符由26个英文字符大小写,数字0-9,符号_$。注意:数字不能开头。 3.java中是严格分大小写。 4.在实际写程序的过程中定义标识符遵守“见名之意”。   类名和接口的规范: 每个单词的首字母大写。(驼峰模式)XxxYyy   如:PersonService   变量名和方法名: 第一个首字母小写,其余的首字母大写。xxxYyyZzz。如:personDao   包名: 全小写。xxx.yyy.zzz   常量: 所有字符都大写,多个单词之间使用下划线分割 关键字 jdk定义的标识符就是关键字。 java的注释 多行注释:    /*。。。。*/ 单行注释:   // 文档注释:   /** ….*/

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值