java 对象实际占用内存大小预估工具类ObjectSizeUtil

java 对象实际占用内存大小预估工具类

返回对象占用预估字节数

返回字节数对应格式化后的字符串(xx Kb)

使用效果
在这里插入图片描述
在这里插入图片描述
依赖了lombock和hutool,项目不用这个可以去掉日志,稍微改写一下。


import cn.hutool.core.util.ClassUtil;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;/*** @author humorchen* date: 2024/4/1* description: 对象大小计算工具**/
@Slf4j
public class ObjectSizeUtil {/*** 嵌套深度不超过10层*/public static int MAX_DEPTH = 10;/*** 单位*/public static final String[] UNIT_NAMES = new String[]{"B", "KB", "MB", "GB", "TB", "PB", "EB"};/*** 字段缓存*/private static final Map<Class<?>, Field[]> FIELD_CACHE = new ConcurrentHashMap<>();/*** 获取对象大小,接近实际内存大小,不完全等于实际大小,用于快速计算内存大小* 性能测试:三层带List的对象,百万次调用,耗时 196ms** @param o* @return*/public static long estimateObjectSize(Object o) {return estimateObjectSize(o, 0);}/*** 获取对象大小,接近实际内存大小,不完全等于实际大小,用于快速计算内存大小* 性能测试:三层带List的对象,百万次调用,耗时 196ms** @param o* @param depth* @return*/private static long estimateObjectSize(Object o, int depth) {if (o == null) {return 4L;}// 深度兜底if (depth >= MAX_DEPTH) {return 4L;}// 基本类型、基本类型包装类、枚举、数组、集合、Map、注解、其他类Class<?> cls = o.getClass();// 64位机器上每个对象至少有16字节的开销long size = 16L;// 基本类和包装对象 int 的class是java.lang.Integerif (ClassUtil.isBasicType(cls)) {if (cls == Integer.class || cls == Float.class) {size += 4L;} else if (cls == Long.class || cls == Double.class) {size += 8L;} else if (cls == Short.class || cls == Byte.class) {size += 2L;} else if (cls == Character.class || cls == Boolean.class) {size += 1L;}} else if (cls == String.class) {// 字符串,每个字符2字节size += 2L * ((String) o).length();} else if (cls.isEnum()) {// 枚举为常量,内存占用视为一个对象引用地址4字节size = 4L;} else if (cls.isAnnotation()) {// 注解 内存占用视为一个对象引用地址4字节size = 4L;} else if (cls.isArray()) {// 数组 遍历数组中的每个元素,递归调用estimateObjectSize方法,数组里每个对象指针4字节int len = Array.getLength(o);for (int i = 0; i < len; i++) {size += estimateObjectSize(Array.get(o, i), depth + 1) + 4;}} else if (o instanceof Collection) {// 集合 遍历集合中的每个元素,递归调用estimateObjectSize方法Collection<?> collection = (Collection<?>) o;if (!collection.isEmpty()) {for (Object obj : collection) {// 集合里每个对象指针4字节size += estimateObjectSize(obj, depth + 1) + 4;}}} else if (o instanceof Map) {// Map 遍历Map中的每个元素,递归调用estimateObjectSize方法Map<?, ?> map = (Map<?, ?>) o;if (!map.isEmpty()) {for (Map.Entry<?, ?> entry : map.entrySet()) {// 集合里每个对象指针4字节 *2size += 8;size += estimateObjectSize(entry.getKey(), depth + 1);size += estimateObjectSize(entry.getValue(), depth + 1);}}} else {// 其他类,遍历类中的每个字段,递归调用estimateObjectSize方法,计算字段的内存占用,field获取每次执行都会拷贝,所以用缓存Field[] declaredFields = FIELD_CACHE.computeIfAbsent(cls, k -> {// 获取类声明的字段,会拷贝Field[]Field[] fields = getDeclaredFields(cls);// 设置可访问for (Field field : fields) {field.setAccessible(true);}return fields;});for (Field declaredField : declaredFields) {try {// 静态的字段直接算一个指针的内存if (Modifier.isStatic(declaredField.getModifiers())) {size += 4L;} else {// 当前字段的这个指针的内存占用加指向的对象内存占用Object object = declaredField.get(o);size += estimateObjectSize(object, depth + 1) + 4;}} catch (Exception e) {log.error("获取对象大小异常", e);}}}return size;}/*** 获取类声明的字段** @param cls* @return*/private static Field[] getDeclaredFields(Class<?> cls) {Set<Field> set = new LinkedHashSet<>();Class<?> currentClass = cls;int depth = 0;while (!Object.class.equals(currentClass) && depth < MAX_DEPTH) {set.addAll(Arrays.asList(currentClass.getDeclaredFields()));currentClass = currentClass.getSuperclass();depth++;}return set.toArray(new Field[0]);}/*** 格式化字节数** @param size* @return*/public static String formatSize(long size) {if (size <= 0) {return "0";}int digitGroups = Math.min(UNIT_NAMES.length - 1, (int) (Math.log10(size) / Math.log10(1024)));return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + UNIT_NAMES[digitGroups];}
}

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

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

相关文章

JavaScript中的Function

** 一、Function ** 什么是&#xff1a; 用途&#xff1a;保存一段可重用的代码段的程序结构&#xff0c;再起一个名字。本质&#xff1a;内存中保存一段代码段的存储空间------对象为什么&#xff1a;只要一段代码&#xff0c;可能被反复使用时&#xff0c;都要定义在一个函…

Shell 学习笔记 - 变量的删除、替换和替代 + 变量中的特殊符号

1.9 Shell 变量的删除、替换和替代 Linux 提供一些可以直接对变量进行操作的符号。通过这些符号&#xff0c;变量中的部分内容可以被删除、替换和替代。在 Shell 中&#xff0c;变量的删除、替换和替代也是非常重要的。通过简单操作修改变量&#xff0c;可以减少代码的行数并提…

docker怎么拉取全部镜像,打包所有镜像

因为docker&#xff0c;所以我把电脑上之前的镜像全部打包出来了 你们也可以打包&#xff0c;我提供一个脚本&#xff0c;你运行即可 export_docker.sh #!/bin/bash# 导出目录 EXPORT_DIR"docker_images_backup" mkdir -p "$EXPORT_DIR"# 获取所有镜像 …

编程第一课名字怎么写:创意、吸引力与实用性的完美结合

编程第一课名字怎么写&#xff1a;创意、吸引力与实用性的完美结合 在编程教育的世界里&#xff0c;为第一课起一个引人入胜的名字至关重要。这个名字不仅要能够吸引学生的注意&#xff0c;还要能够准确地传达课程的核心内容和价值。那么&#xff0c;如何为编程第一课起一个既…

PythonPoc基础编写(3)---批量刷cnvd

文章目录 前言一、发现过程二、使用步骤1.引入库2.读入数据结果 总结 前言 想刷cnvd&#xff1f;最重要的是登录进行测试功能点 一、发现过程 找到一个网站 发现登录失败返回200 登录成功则是重定向 302 那就写一个脚本吧 二、使用步骤 1.引入库 import requests 2.读入…

Docker容器技术在Linux平台的应用与实践

Docker容器技术自推出以来&#xff0c;迅速成为Linux平台上应用部署和微服务架构的首选方案&#xff0c;它通过轻量级的隔离机制&#xff0c;实现了应用程序及其依赖环境的一致性部署与管理。以下是Docker容器技术在Linux平台上的主要应用与实践领域&#xff1a; 1. 应用快速部…

Web Works API 和 Promise 的对比和区别

Web Workers 和 Promise 都是强大的工具&#xff0c;用于不同的异步处理场景。Web Workers 适用于需要并行处理的复杂任务&#xff0c;通过后台线程避免阻塞主线程。而 Promise 则简化了单线程中的异步操作管理&#xff0c;使代码更加清晰和结构化。根据具体需求选择合适的技术…

安装AutoCAD异常

问题&#xff1a; 安装Autodesk产品时&#xff0c;显示以下消息&#xff0c;且安装未完成。 正在等待操作系统重新启动。 请重新启动计算机以安装 AutoCAD 2024。 操作系统&#xff1a; Windows 10Windows 11 原因&#xff1a; Windows注册表项已损坏。Microsoft Visual C …

生产环境下部署微调的10条戒律

关于大模型微调部署,openPile,Kyle Corbitt的《Ten Commandments to Deploy Fine-Tuned Models inProd》:https://docs.google.com/presentation/d/1lRrTEDOw7160sU_-PL5bONLOPq_7E8alewvcJ01BCE/edit#slideid.g2721fb6713e_0_44 1、第一戒律:不可微调&#xff0c;直接使用提示…

CDN内容加速原理?

1.用户向浏览器提供要访问的域名 2.浏览器从本地host文件中解析域名,如何host文件没有做任何配置&#xff0c;则浏览器调用域名解析库对域名进行解析,析函数库一般得到的是该域名对应的CNAME记录,从中获取真正的IP地址,此过程中,根据地理位置信息解析对应的IP地址&#xff0c;…

微射流均质机可用于纳米制剂和材料制备 我国市场需求空间广阔

微射流均质机可用于纳米制剂和材料制备 我国市场需求空间广阔 微射流均质机是一种纳米级乳化及分散的处理设备&#xff0c;工作原理是在加压状态下&#xff0c;高压流体经过微细孔径喷嘴后&#xff0c;形成高速微射流&#xff0c;从而产生强大的涡流和切应力&#xff0c;将颗粒…

ESP8266-01S烧录MQTT固件ERROR问题

今天在烧录ESP8266固件时遇到了这个问题&#xff0c;技术客服给了个有效的解决方案。 选择固件的时候可以先确认自己的模块是ESP8266或者EPS8285主控&#xff0c;这在选择DOWNLOADTOOL时还不一样。 然后波特率是115200&#xff0c;我在这个地方选错成1152000。 当然上面都不…

PHP 日期处理完全指南

PHP 日期处理完全指南 引言 在PHP开发中,日期和时间处理是一个常见且重要的任务。PHP提供了丰富的内置函数来处理日期和时间,包括日期的格式化、计算、解析等。本文将详细介绍PHP中日期处理的相关知识,帮助读者全面理解和掌握这一技能。 1. PHP日期函数基础 1.1 date()函…

【ARM Cache 及 MMU 系列文章 1.4 -- 如何判断 L3 Cache 是否实现?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cluster Configuration Register代码实现什么是Single-Threaded Core?什么是PE(Processor Execution units)?Single-Threaded Core与PE的关系对比多线程(Multithreading)Cluster…

LeetCode-day15-522. 最长特殊序列 II

LeetCode-day15-522. 最长特殊序列 II 题目描述示例示例1&#xff1a;示例2&#xff1a; 思路代码 题目描述 给定字符串列表 strs &#xff0c;返回其中 最长的特殊序列 的长度。如果最长特殊序列不存在&#xff0c;返回 -1 。 特殊序列 定义如下&#xff1a;该序列为某字符串…

用java 做一个模拟的菜单及对话框测试

首先我们要创建一个Menu 的java类 然后接着给上代码 代码如下&#xff1a; package test01;import javax.swing.*;public class Menu extends JFrame{JMenuBar jmb;JMenu jmfile,jmedit,jmhelp;JMenuItem jminew,jmiopen,jmisave,jmisaveas,jmiexit,jmicut,jmicopy,jmipast…

gridview自带编辑功能如何判断用户修改的值的合法性

在使用GridView的编辑功能更新值时&#xff0c;确保输入的值合法性是十分重要的。为了实现这一点&#xff0c;你可以在GridView的RowUpdating事件中加入代码来检查用户输入的值。如果发现输入的值不合法&#xff0c;你可以取消更新操作并向用户显示错误消息。下面是如何实现的步…

小区噪音监测管理系统设计

一、引言 随着城市化进程的加快&#xff0c;小区居民对于居住环境的要求日益提高。其中&#xff0c;噪音污染已成为影响居民生活质量的重要因素。因此&#xff0c;设计一套小区噪音监测管理系统&#xff0c;对于提升居民的生活品质和小区管理效率具有重要意义。本文将详细阐述…

一五二、go缓存GCache和Go-Redis

GCache 和 Go-Redis 都是 Go 语言中常用的缓存解决方案&#xff0c;但它们适用于不同的场景。以下是它们各自的特点和适用场景。 GCache GCache 是一个内存缓存库&#xff0c;主要用于在单个应用程序实例中缓存数据。它具有以下特点&#xff1a; 本地缓存&#xff1a;缓存数…

React useReducer 使用及 useImmerReducer

useReducer 实际上是以数组上的 reduce() 方法命名的。 传递给 reduce 的函数被称为 “reducer”。它接受 目前的结果 和 当前的值&#xff0c;然后返回 下一个结果。 React 中的 reducer 和这个是一样的&#xff1a;它们都接受 目前的状态 和 action &#xff0c;然后返回 下一…