背景:
前段时间,生产环境出现问题:日期不一致,然后发现:SimpleDateFormat不是线程安全的类。
为什么将SimpleDateFormat 变量静态化呢
static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
初衷是每创建 simpleDateFormat 对象,需要比较大的内存。
问题:找到 创建一个simpleDateFormat 对象,需要多大的内存?
运行命令: java -javaagent:testload-0.0.1-SNAPSHOT.jar com.atzy.tango.test.SizeOfObjectTest
下载地址:https://download.youkuaiyun.com/download/spark_guo/10658391
以下是代码段,
package com.atzy.tango.test;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;
/**
* 对象占用字节大小工具类
* @author Spark.Guo
*
* @version 创建时间:2018年9月3日 下午5:04:25
*/
public class SizeOfObject {
static Instrumentation inst;
public static void premain(String args, Instrumentation instP) {
inst = instP;
}
/**
* 直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、<br></br>
* 引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小;<br></br>
* 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小 <br></br>
*
* @param obj
* @return
*/
public static long sizeOf(Object obj) {
return inst.getObjectSize(obj);
}
/**
* 递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小
*
* @param objP
* @return
* @throws IllegalAccessException
*/
public static long fullSizeOf(Object objP) throws IllegalAccessException {
Set<Object> visited = new HashSet<Object>();
Deque<Object> toBeQueue = new ArrayDeque<Object>();
toBeQueue.add(objP);
long size = 0L;
while (toBeQueue.size() > 0) {
Object obj = toBeQueue.poll();
//sizeOf的时候已经计基本类型和引用的长度,包括数组
size += skipObject(visited, obj) ? 0L : sizeOf(obj);
Class<?> tmpObjClass = obj.getClass();
if (tmpObjClass.isArray()) {
//[I , [F 基本类型名字长度是2
if (tmpObjClass.getName().length() > 2) {
for (int i = 0, len = Array.getLength(obj); i < len; i++) {
Object tmp = Array.get(obj, i);
if (tmp != null) {
//非基本类型需要深度遍历其对象
toBeQueue.add(Array.get(obj, i));
}
}
}
} else {
while (tmpObjClass != null) {
Field[] fields = tmpObjClass.getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers()) //静态不计
|| field.getType().isPrimitive()) { //基本类型不重复计
continue;
}
field.setAccessible(true);
Object fieldValue = field.get(obj);
if (fieldValue == null) {
continue;
}
toBeQueue.add(fieldValue);
}
tmpObjClass = tmpObjClass.getSuperclass();
}
}
}
return size;
}
/**
* String.intern的对象不计;计算过的不计,也避免死循环
*
* @param visited
* @param obj
* @return
*/
static boolean skipObject(Set<Object> visited, Object obj) {
if (obj instanceof String && obj == ((String) obj).intern()) {
return true;
}
return visited.contains(obj);
}
}
package com.atzy.tango.test;
import static com.atzy.tango.test.SizeOfObject.fullSizeOf;
import static com.atzy.tango.test.SizeOfObject.sizeOf;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
/**
*
* @author Spark.Guo
*
* @version 创建时间:2018年9月3日 下午5:04:35
*/
public class SizeOfObjectTest {
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24
*/
static class A {
int a;
}
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24
*/
static class B {
int a;
int b;
}
/**
* -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
* -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32
*/
static class B2 {
int b2a;
Integer b2b;
}
/**
* 不考虑对象头:
* 4 + 4 + 4 * 3 + 3 * sizeOf(B)
*/
static class C extends A {
int ba;
B[] as = new B[3];
C() {
for (int i = 0; i < as.length; i++) {
as[i] = new B();
}
}
}
static class D extends B {
int da;
Integer[] di = new Integer[3];
}
/**
* 会算上A的实例字段
*/
static class E extends A {
int ea;
int eb;
}
public static void main(String[] args) throws Exception {
// System.out.println(new File("target/classes").getAbsolutePath());
System.out.println("sizeOf(new Object())=" + sizeOf(new Object()));
System.out.println("sizeOf(new A())=" + sizeOf(new A()));
System.out.println("sizeOf(new B())=" + sizeOf(new B()));
System.out.println("sizeOf(new B2())=" + sizeOf(new B2()));
System.out.println("sizeOf(new B[3])=" + sizeOf(new B[3]));
System.out.println("sizeOf(new C())=" + sizeOf(new C()));
System.out.println("fullSizeOf(new C())=" + fullSizeOf(new C()));
System.out.println("sizeOf(new D())=" + sizeOf(new D()));
System.out.println("fullSizeOf(new D())=" + fullSizeOf(new D()));
System.out.println("sizeOf(new int[3])=" + sizeOf(new int[3]));
System.out.println("sizeOf(new Integer(101189192)=" + sizeOf(new Integer(101189192)));
System.out.println("sizeOf(new Integer[0])=" + sizeOf(new Integer[0]));
System.out.println("sizeOf(new Integer[1])=" + sizeOf(new Integer[1]));
System.out.println("sizeOf(new Integer[2])=" + sizeOf(new Integer[2]));
System.out.println("sizeOf(new Integer[3])=" + sizeOf(new Integer[3]));
System.out.println("sizeOf(new Integer[4])=" + sizeOf(new Integer[4]));
System.out.println("sizeOf(new A[3])=" + sizeOf(new A[3]));
System.out.println("sizeOf(new E())=" + sizeOf(new E()));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("sizeOf(new SimpleDateFormat=" + fullSizeOf(simpleDateFormat));
System.out.println("format:"+simpleDateFormat.format(new Date()));
System.out.println("sizeOf(new SimpleDateFormat format=" + fullSizeOf(simpleDateFormat));
try {
System.out.println("parse:"+simpleDateFormat.parse("2018-07-09 18:24:30"));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("sizeOf(new SimpleDateFormat parse=" + fullSizeOf(simpleDateFormat));
DateFormatUtils dateFormatUtils = new DateFormatUtils();
System.out.println("sizeOf(new dateFormatUtils parse=" + fullSizeOf(dateFormatUtils));
System.out.println(dateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
System.out.println("sizeOf(new dateFormatUtils parse=" + fullSizeOf(dateFormatUtils));
String[] tArray = new String[1];
tArray[0] ="2018-07-09 18:24:30";
DateUtils dateUtils = new DateUtils();
System.out.println("sizeOf(new dateUtils parse=" + fullSizeOf(dateUtils));
dateUtils.parseDate("2018-07-09 18:24:30", tArray);
System.out.println("sizeOf(new dateUtils parse=" + fullSizeOf(dateUtils));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com</groupId>
<artifactId>testload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>testload</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<java.rt>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</java.rt>
</properties>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>org.apache.sanselan</groupId>
<artifactId>sanselan</artifactId>
<version>0.97-incubator</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Premain-Class>com.atzy.tango.test.SizeOfObject</Premain-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>