简析Go与Java内存管理的差异

本文对比分析了Go和Java在内存管理方面的差异,包括内存结构、对象分配和垃圾回收策略。Go采用分层级内存管理模式,而Java实行分代管理。Go的mcache与Java的TLAB类似,为线程提供快速内存分配。Java使用元数据区存储字节码,Go直接将程序指令加载到内存。两者GC策略不同,Go使用非分代、并发标记清理,Java采用分代收集,如新生代的“标记-复制”和老年代的“标记-清理”或“标记-整理”。
摘要由CSDN通过智能技术生成

前言
从实践中看,Golang(以下简称Go)应用程序比Java占用更少的内存,这与它们的运行时环境有关,其运行时自带了内存动态分配和自动垃圾回收的管理机制,本文通过分析Go与Java在内存管理机制上的差异,以期对两者在运行时内存方面有更进一步的认识。本文以Go(1.12)和当前使用较多的JDK8 HotSpot VM为例进行说明。

本篇文章包含以下内容:

介绍Go与Java的运行时内存结构差异

介绍Go与Java的内存资源占用差异

介绍Go与Java如何为对象分配内存

介绍Go与Java的内存回收策略差异

在这里插入图片描述

内存结构差异

应用程序要能在linux系统上运行(其他平台类似),其可执行文件要求符合ELF规范(Executable and Linkable Format,可执行和可链接格式)。操作系统加载目标可执行文件到内存中并以独立进程方式运行程序。

操作系统为每个进程分配一个连续的虚拟内存地址空间,并将该进程内存空间划分成多个不同用途的逻辑区域。JVM进程以及Go进程的内存结构如下图所示:

在这里插入图片描述图1

Java用户程序是运行在Java虚拟机(以下简称“JVM”)之上的,从上图我们看到用户程序的字节码指令并没有存储到JVM进程的堆空间或者text段中。实际上,虚拟机将用户程序字节码放在了使用本地直接内存实现的方法区中,并不占用虚拟机的堆内存。

JVM的堆空间保存Java用户程序运行时创建的对象和字符串常量池等数据,栈空间则为Java线程提供了私有的内存区域。在HotSpot VM的实现中,Java线程栈使用操作系统栈和线程模型表示,且Java方法与本地方法共享同一个栈区。因此虚拟机栈与本地方法栈其实是同一个区域。

Go与Java有较大不同,Go进程空间的text段不但保存了内置的运行时机器指令,而且还有用户程序的机器指令(Go在编译时就已确定)。堆内存区则为用户程序创建对象提供了存储空间。Go天然支持并发编程模型,采用了系统线程与用户线程(goroutine)相结合的实现机制,进程栈空间为系统线程提供了栈内存,而用户线程栈的内存默认从堆中分配。

Java内存结构

  1. 运行时内存

Java程序的运行时内存被划分为元数据区(方法区)、堆、虚拟机栈、本地方法栈、程序计数器5个部分,这可以看作是JVM对进程可用堆、栈空间进行的二次分配,以满足运行Java用户程序的内存需求。其内存结构如下图所示:

在这里插入图片描述
图2

上图中堆内存对应了图1中JVM的堆内存,虚拟机栈、本地方法栈、程序计数器则对应了图1中JVM的栈区,元数据区则是JVM另外开辟的内存块。

· 元数据区是JVM向操作系统申请的堆外内存,用于实现“方法区”,主要存储虚拟机加载class的类信息、JIT编译的代码、运行时常量池等数据,其默认大小由系统的可用物理内存上限限制。

· 堆内存是被所有线程共享的一块内存区域,在虚拟机启动时创建。它存放了包括几乎所有的Java对象以及数组,这也是垃圾收集器关注的主要内存区。由于逃逸分析等优化技术,对象也有可能被分配到栈上。

· 虚拟机栈即我们常说的栈空间,其生命周期与线程相同。线程的栈空间存储了方法调用的栈帧,每个栈帧则存储局部变量表、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值