当前位置: 首页 > news >正文

【Java算法】内存分析

文章目录

  • 前言
  • 一个对象的内存占用情况
  • 链表
  • 数组
  • 字符串对象
  • 字符串的值和子字符串

前言

典型的 Java 实现使用 8 位表示字节,用 2 字节(16 位)表示一个 char 值,
用 4 字节(32 位)表示一个 int 值,用 8 字节(64 位)表示一个 double 或者 long 值,用 1 字节表示一个 boolean 值(因为计算机访问内存的方式都是一次 1 字节)。根据可用内存的总量就能够计算出保存这些值的极限数量。例如,如果计算机有 1 GB 内存(10 亿字节),那么同一时间最多能在内存中保存 2.56 亿万个 int 值或是 1.28 亿万个 double 值。
许多数据结果都涉及对机器地址的表示,而在各种计算机中一个机器地址所需的内存又各有不同。为了保持一致,假设表示机器地址需要 8 字节(C语言中的指针就是这个大小),这是现在广泛使用的 64 位构架中的典型表示方式,许多老式的 32 位构架只使用 4 字节表示机器地址。

一个对象的内存占用情况

要知道一个对象所使用的内存量,需要将所有实例变量使用的内存与对象本身的开销(一般是16 字节)相加。这些开销包括一个指向对象的类的引用、垃圾收集信息以及同步信息。另外,一般内存的使用都会被填充为8字节(64位计算机中的机器字)
的倍数。例如,一个 Integer 对象会使用 24 字节(16字节的对象开销,4 字节用于保存它的 int 值以及 4个填充字节)。类似地,一个Date对象需要使用 32 字节:16 字节的对象开销,3 个 int 实例变量各需 4 字节,以及 4 个填充字节。对象的引用
一般都是一个内存地址,因此会使用 8 字节。例如,一个 Counter 对象需要使用 32 字节:16 字节的对象开销,8 字节用于它的 String 型实例变量(一个引用),4 字节用于 int 实例变量,以及4 个填充字节。当我们说明一个引用所占的内存时,我们会单独说明它所指向的对象所占用的内存,因此这个内存使用总量并没有包含 String 值所使用的内存。
在这里插入图片描述
在这里插入图片描述

链表

嵌套的非静态(内部)类,例如我们的Node类,还需要额外的 8 字节(用于一个指
向外部类的引用)。因此,一个 Node 对象需要使用 40 字节(16 字节的对象开销,指向 Item 和 Node对象的引用各需 8 字节,另外还有 8 字节的额外开销)。因为 Integer 对象需要使用 24 字节,一个含
有 N 个整数的基于链表的栈(请见算法 1.2)需要使
用(32+64N)字节,包括 Stack 对象的 16 字节的开
销,引用类型实例变量8字节,int型实例变量4字节,
4 个填充字节,每个元素需要 64 字节,一个 Node 对象的 40 字节和一个 Integer 对象的 24 字节。

数组

Java 中数组被实现为对象,它们一般都会因为记录长度而需要额外的内存。一个原始数据类型的数组一般需要 24 字节的头信息(16字节的对象开销,4 字节用于保存长度以及 4 填充字节)再加上保存值所需的内存。例如,一个含有 N 个 int 值的数组需要使用(24 + 4N)字节(会被填充为 8 的倍数),一个含有 N 个 double值的数组需要使用(24 + 8N)字节。一个对象的数组就是一个对象的引用的数组,所以我们应该在对象所需的内存之外加上引用所需的内存。例如,一个含有 N 个 Date 对象的数
组需要使用 24 字节(数组开销)加上 8N 字节(所有引用)加上每个对象的 32 字节,总共(24 + 40N)字节。二维数组是一个数组的数组(每个数组都是一个对象)。例如,一个 M×N 的 double类型的二维数组需要使用 24 字节(数组的数组的开销)加上 8M 字节(所有元素数组的引用)加上 24M 字节(所有元素数组的开销)加上 8MN 字节(M 个长度为 N 的 double 类型的数组),总共(8MN+32M+24)~ 8MN 字节;当数组元素是对象时计算方法类似,结果相同,用来保存充满指向数组对象的引用的数组以及所有这些对象本身。

字符串对象

我们可以用相同的方式说明 Java 的 String 类型对象所需的内存,只是对于字符串来说别名是非常常见的。String 的标准实现含有 4 个实例变量:一个指向字符数组的引用(8 字节)和三个 int 值(各 4 字节)。第一个 int 值描述的是字符数组中的偏移量,第二个 int 值是一个计数器(字符串的长度)。按照下图所示的实例变量名,对象所表示的字符串由 value[offset]到 value[offset + count - 1] 中的字符组成。String 对象中的第三个 int 值是一个散列值,它在某些情况下可以节省一些计算,现在可以忽略它。因此,每个 String 对象总共会使用字节(16 字节表示对象,三个 int 实例变量各需 4 字节,加上数组引用的 8 字节和 4 个填充字节)。这是除字符数组之外字符串所需的内存空间,所有字符所需的内存需要另记,因为 String 的 char数组常常是在多个字符串之间共享的。因为 String 对象是不可变的,这种设计使 String 的实现在能够在多个对象都含有相同的 value[] 数组时节省内存。
在这里插入图片描述

字符串的值和子字符串

一个长度为 N 的 String 对象一般需要使用 40 字节(String 对象本身)加(24+2N)字节(字符数组),总共(64+2N)字节。但字符串处理经常会和子字符串打交道,所以 Java 对字符串的表示希望能够避免复制字符串中的字符。当你调用 substring() 方法时,就创建了一个新的 String对象(40 字节),但它仍然重用了相同的 value[] 数组,因此该字符串的子字符串只会使用 40 字节的内存。含有原始字符串的字符数组的别名存在于子字符串中,子字符串对象的偏移量和长度域标记了子字符串的位置。换句话说,一个子字符串所需的额外内存是一个常数,构造一个子字符串所需的时间也是常数,即使字符串和子字符串的长度极大也是这样。某些简陋的字符串表示方法在创建子字符串时需要复制其中的字符,这将需要线性的时间和空间。确保子字符串的创建所需的空间(以及时间)和其长度无关是许多基础字符串处理算法的效率的关键所在。字符串的值与子字符串示例如上图所示。这些基础机制能够有效帮助我们估计大量程序对内存的使用情况,但许多复杂的因素仍然会使这个任务变得更加困难。我们已经提到了别名可能产生的潜在影响。另外,当涉及函数调用时,内存的消耗就变成了一个复杂的动态过程,因为 Java 系统的内存分配机制扮演一个重要的角色,而这套机制又和 Java 的实现有关。例如,当你的程序调用一个方法时,系统会从内存中的一个特定区域为方法分配所需要的内存(用于保存局部变量),这个区域叫做栈(Java 系统的下压栈)。当方法返回时,它所占用的内存也被返回给了系统栈。因此,在递归程序中创建数组或是其他大型对象是很危险的,因为这意味着每一次递归调用都会使用大量的内存。当通过 new 创建对象时,系统会从堆内存的另一块特定区域为该对象分配所需的内存。而且,你要记住所有对象都会一直存在,直到对它的引用消失为止。此时系统的垃圾回收进程会将它所占用的内存收回到堆中。这种动态过程使准确估计一个程序的内存使用变得极为困难。

相关文章:

  • 深度学习:卷积神经网络保姆级详细指南
  • 【云原生之Docker实战】使用Docker部署Duplicati备份工具
  • Qt 游戏场景 图元
  • 二叉树难题破解
  • 【算法面试必刷Java版二十】数组中的逆序对
  • Postman接口断言上下游参数传递
  • Amazon S3 Compatibility 兼容API 封装AWS S3工具类 生成预前面url跨域问题解决
  • 请问各位大神如何写论文的摘要?
  • C++ 基础语法
  • 什么是ForkJoin
  • OpenCV-漫水填充cv::floodFill
  • 【精品】SpringSecurity在前后端分离项目中的应用
  • MySQL知识点总结_1
  • 深入理解Python生成器
  • SpringBoot+Vue项目校园商铺系统
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 10个最佳ES6特性 ES7与ES8的特性
  • Android 控件背景颜色处理
  • Android交互
  • JS函数式编程 数组部分风格 ES6版
  • nodejs调试方法
  • STAR法则
  • Vue.js-Day01
  • 半理解系列--Promise的进化史
  • 大型网站性能监测、分析与优化常见问题QA
  • 老板让我十分钟上手nx-admin
  • 判断客户端类型,Android,iOS,PC
  • 区块链分支循环
  • 听说你叫Java(二)–Servlet请求
  • 详解NodeJs流之一
  • 【干货分享】dos命令大全
  • #图像处理
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (阿里云万网)-域名注册购买实名流程
  • (二十三)Flask之高频面试点
  • (理论篇)httpmoudle和httphandler一览
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (十一)图像的罗伯特梯度锐化
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)nsfocus-绿盟科技笔试题目
  • .apk 成为历史!
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .Net MVC + EF搭建学生管理系统
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET中 MVC 工厂模式浅析
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • .stream().map与.stream().flatMap的使用
  • /3GB和/USERVA开关
  • [ IO.File ] FileSystemWatcher
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [120_移动开发Android]008_android开发之Pull操作xml文件