Java中的对象一定在堆上分配吗?

首先,为解释这个问题,需要的基本知识如下(如果对以下概念不太熟悉, 可以先了解下):

1.JVM内存结构,传送门
2.即时编译(JIT),传送门
3. 逃逸分析,传送门

Java对象内存分配策略

一般认为,Java对象都是在堆上分配的,但也有一些特殊情况。Java对象内存分配策略:

在这里插入图片描述

在Java中,典型的对象不在堆上分配的情况有两种:TLAB(Thread Local Allocation Buffer)和栈上分配(严格来说TLAB也是属于堆,只是在TLAB比较特殊)。

一 、栈上分配

JVM在Server模式下的逃逸分析可以分析出某个对象是否永远只在某个方法、线程的范围内,并没有“逃逸”出这个范围,逃逸分析的一个结果就是对于某些未逃逸对象可以直接在栈上分配,由于该对象一定是局部的,所以栈上分配不会有问题。在实际的应用程序,尤其是大型程序中反而发现实施逃逸分析可能出现效果不稳定的情况,或因分析过程耗时但却无法有效判别出非逃逸对象而导致性能(即时编译的收益)有所下降,所以在很长的一段时间里,即使是Server Compiler,也默认不开启逃逸分析,甚至在某些版本(如JDK 1.6 Update18)中还曾经短暂地完全禁止了这项优化。

二 、TLAB分配

对象创建在虚拟机中是非常频繁的行为,即使是仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。

解决这个问题有两种方案,一种是对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS和失败重试的方式保证更新操作的原子性;另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。

JVM在内存新生代Eden Space中开辟了一小块区域,由线程私有,称作TLAB(Thread-local allocation buffer),默认设定为占用Eden Space的1%。在Java程序中很多对象都是小对象且用过即丢,它们不存在线程共享也适合被快速GC,所以对于小对象通常JVM会优先分配在TLAB上,并且TLAB上的分配由于是线程私有所以没有锁开销。因此在实践中分配多个小对象的效率通常比分配一个大对象的效率要高。

哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。通常默认的TLAB区域大小是Eden区域的1%,当然也可以手工进行调整,对应的JVM参数是-XX:TLABWasteTargetPercent。

三 、为什么不直接在堆上分配

我们知道堆是由所有线程共享的,既然如此那它就是竞争资源,对于竞争资源,必须采取必要的同步,所以当使用new关键字在堆上分配对象时,是需要锁的。既然有锁,就必定存在锁带来的开销,而且由于是对整个堆加锁,相对而言锁的粒度还是比较大的,影响效率。而无论是TLAB还是栈都是线程私有的,私有即避免了竞争。

所以对于某些特殊情况,可以采取避免在堆上分配对象的办法,以提高对象创建和销毁的效率。

四 、对象内存分配的两种方法

为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。

1) 指针碰撞(Serial、ParNew等带Compact过程的收集器)

假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump the Pointer)。

2)空闲列表(CMS这种基于Mark-Sweep算法的收集器)

如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)。

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。因此,在使用Serial、ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最全的 netcore 3.0 升级实战方案

1、哈喽大家中秋节(后)好呀!感觉已经好久没有写文章了,但是也没有偷懒哟,我的视频教程《系列一、NetCore 视频教程(Blog.Core)》也已经录制八期了,还在每周末同步更新中,…

微软发布.Net Core 3.0 RC1,最终版本定于9月23日

2019.9.17 微软 宣布推出.NET Core 3.0 Release Candidate 1。就像Preview 9一样,主要专注于为 .NET Core 3.0 发布最终版本 。现在变得非常非常接近。将在9月23日.NET Conf上发布最终版本。.NET Core 3.0是从仅支持Windows传统的 .NET框架向更现代化的开源实现过渡…

JVM内存结构 VS Java内存模型 VS Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和Java对象模型,这就是三个截然不同的概念&…

迫于误解压力,RMS从自由软件基金会与MIT离职

自由软件基金会官网显示,基金会创始人兼主席、自由软件运动发起人 Richard M. Stallman(RMS)辞去主席职务并辞去董事会职务。而另一边,stallman.org 邮件列表显示,RMS 已经从麻省理工学院(MIT)计…

让人迷茫的三十岁!从专业技能、行业知识和软实力谈一下!

作者:邹溪源,长沙资深互联网从业者,架构师社区合伙人!我今年三十岁,我很迷茫,不知道未来该选择什么发展方向。这是我无意中在社区微信群中看到的一位年轻的开发者说的话,之前他也经常会在技术群…

误用.Net Redis客户端工具CSRedisCore,自己挖坑自己填

前导  上次Redis MQ分布式改造完成之后, 编排的容器稳定运行了一个多月,昨天突然收到ETL端同事通知,没有采集到解析日志了。赶紧进服务器看了一下,用于数据接收的receiver容器挂掉了, 尝试docker container start [c…

Java——类加载机制

** 一、什么是类的加载 ** 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class…

.NET中国峰会议题征集

月初做的调查《》,参与人数576人,愿意参与分享.NET Core经验的142人,今天发起分会场主题演讲和闪电演讲议题.2014年微软组织成立.NET基金会,微软在成为主要的开源参与者的道路上又前进了一步。2014年以来已经有众多知名公司加入.N…

一些学习教程资料等你来拿

近期整理自己的云盘中发现近年来私藏了很多学习资料和教程,本着独乐乐不如众乐乐的精神,特将其分享出来供有兴趣的童鞋学习。进入公众号,输入关键词"敏捷"/"agile"/"scrum",即可获得敏捷开发类别的…

Java——编译与反编译

** 一、基础知识 ** 1.1 编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language)。编程语言(Programming Language)分为低级语言(Low-level Language)和高级语…

程序员自家种水果,新鲜包邮配送

上次猕猴桃的活动<好多小伙伴&#xff0c;买了一箱尝过后又下单了好几箱。事实证明&#xff0c;品质才是销量的最佳保证。有些粉丝找到我说&#xff0c;自己家也有果园自己种水果&#xff0c;都是当天采摘当天发货的纯天然水果。于是他们给我寄了一些自家种的苹果、香瓜、冬…

【招聘(广州)】-年薪30W起-自助打印领域业内第一

印萌是一家为高校打印店提供整套“无人自助打印”解决方案的互联网科技公司&#xff0c;已获得数百万元融资&#xff0c;公司正向盈利。目前产品覆盖清华大学、北京大学、中山大学、复旦大学、浙江大学等700多所高校&#xff0c;多达1800间打印店&#xff0c;累计为全国1200万大…

尾递归

1、递归 简单的来说递归就是一个函数直接或间接地调用自身&#xff0c;是为直接或间接递归。一般来说&#xff0c;递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时&#xff0c;递归前进&#xff1b;当边界条件满足时&#xff0c;递归返回。 用递归需要注意以…

多场景抢红包业务引发.NETCore下使用适配器模式实现业务接口分离

事情的起因我们公司现有一块业务叫做抢红包&#xff0c;最初的想法只是实现了一个初代版本&#xff0c;就是给指定的好友单发红包&#xff0c;随着业务的发展&#xff0c;发红包和抢红包的场景也越来越多&#xff0c;目前主要应用的场景有&#xff1a;单聊发红包、群聊发红包、…

设计模式——创建型模型

目录 单例模式&#xff08;singleton&#xff09;构建模式&#xff08;Builder&#xff09;原型模式&#xff08;Prototype&#xff09;工厂方法模式&#xff08;Factory&#xff09;抽象工厂模式&#xff08;Abstract Factory&#xff09; ** 一、5种创建型模型 ** 1.1 单…

【C】KoobooJson在asp.net core中的使用

版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。本文链接&#xff1a;https://blog.csdn.net/j_teng/article/details/100924973“KoobooJson是一款体积小巧没有任何依赖且性能表现强劲的Json工具…

【DevOps进行时】C/S端界面自动化测试:微软UIAutomation实践

在界面自动化测试领域里存在许多流行的自动化测试工具&#xff0c;例如目前比较受欢迎的开源自动化工具Selenium、Katalon&#xff1b;HP旗下知名的商业软件Unified Functional Testing(更名前叫QTP)&#xff1b;隶属于IBM以数据驱动测试的RTF&#xff08;Rational Functional …

代码编辑器横评:为什么 VS Code 能拔得头筹

2015 年 4 月 29 日的 Build 大会上&#xff0c;微软发布了 Visual Studio Code 第一个预览版本。短短四年时间里&#xff0c;VS Code 高速成长。根据 2019 年 2 月的 PYPL Top IDE index 的排名&#xff0c;VS Code 的涨势迅猛&#xff0c;在所有编辑器与 IDE 中排名第六&…

设计模式——结构型模型

一&#xff1a;目录 1. 装饰者模式&#xff08;Decorator&#xff09; 2. 代理模式&#xff08;Proxy&#xff09; 3. 组合模式&#xff08;Composite&#xff09; 4. 桥接模式&#xff08;Bridge&#xff09; 5. 适配器模式&#xff08;Adapter&#xff09; 6. 蝇量模式&#…

利用Helm简化Kubernetes应用部署(1)

目录利用Helm简化Kubernetes应用部署 Helm基础 安装Helm 使用Visual Studio 2019为Helm编写一个简单的应用 利用Helm简化Kubernetes应用部署Helm是Kubernetes生态系统中的一个软件包管理工具&#xff0c;有点类似于Linux操作系统里面的“apt-get”和“yum”。结合上一节内容&am…