近段时间,项目要求对java的内存有要求,客户希望不要老是要他们扩大内存,所以此过程中了解了一些问题。
越想觉得,java越不是。1,基础对象占有内存 byte,char,short,int,long,float,double分别为 1,2,2,4,8,4,8,byte;
包括后Byte,Short,Integer,Long....等分别为 16,16,16,16,都是byte
本来是 1字节的 byte包装后占 16字节!! 太不象话了,白用我的内存。除了一个Object 8byte指针其它浪费。
2, Object 8byte指针,就算定义个空对象,也一样占8byte 我觉得一个指针要 8个字节吗?有必要吗?我的内存啊。
2^64= 18446744073709551616 byte =17179869184G 有可能用这么大的内存地址吗?(欢迎内行发言)。
个人觉得:6个byte足也,281474976710656 = 262144G 不知道有什么难处要用 8byte.
3, Byte 用了 16字字节,真是想不通:8(指针)+8;浪费7byte
4, Short用了 16字字节,真是想不通:8(指针)+8;浪费6byte
5, Integer 用了 16字字节,真是想不通:8(指针)+8;浪费4byte
6, Long 用了 16字字节,:8(指针)+8;没浪费。
7, Float 用了 16字字节,真是想不通:8(指针)+8;浪费4byte。
8, Double 用了 16字字节,:8(指针)+8;没浪费。
9, BigDecimal 用了 32字字节,:8(指针)+24;除指针外 16不够? 太猛了吧?吃内存啊!!!
10,object = new String(); 用了 40 字字节,:8(指针)+32;好象内存没花钱一样。
11 int[] a =new int[]{0}; 也是16字节
11 long[] a =new long[]{0}; 也是24字节这么基础的东西,做得这样烂,java倒底怎么了? 难道为吃内存而生? 现在知道,为什么java在游戏上插不上足,这样根本是不行的。不用对象,又难以区分数据库为空的数据,真是进退两难。
为什么java不在新版本上来个新架构啊,这样下去只有一条:死.........
越想觉得,java越不是。1,基础对象占有内存 byte,char,short,int,long,float,double分别为 1,2,2,4,8,4,8,byte;
包括后Byte,Short,Integer,Long....等分别为 16,16,16,16,都是byte
本来是 1字节的 byte包装后占 16字节!! 太不象话了,白用我的内存。除了一个Object 8byte指针其它浪费。
2, Object 8byte指针,就算定义个空对象,也一样占8byte 我觉得一个指针要 8个字节吗?有必要吗?我的内存啊。
2^64= 18446744073709551616 byte =17179869184G 有可能用这么大的内存地址吗?(欢迎内行发言)。
个人觉得:6个byte足也,281474976710656 = 262144G 不知道有什么难处要用 8byte.
3, Byte 用了 16字字节,真是想不通:8(指针)+8;浪费7byte
4, Short用了 16字字节,真是想不通:8(指针)+8;浪费6byte
5, Integer 用了 16字字节,真是想不通:8(指针)+8;浪费4byte
6, Long 用了 16字字节,:8(指针)+8;没浪费。
7, Float 用了 16字字节,真是想不通:8(指针)+8;浪费4byte。
8, Double 用了 16字字节,:8(指针)+8;没浪费。
9, BigDecimal 用了 32字字节,:8(指针)+24;除指针外 16不够? 太猛了吧?吃内存啊!!!
10,object = new String(); 用了 40 字字节,:8(指针)+32;好象内存没花钱一样。
11 int[] a =new int[]{0}; 也是16字节
11 long[] a =new long[]{0}; 也是24字节这么基础的东西,做得这样烂,java倒底怎么了? 难道为吃内存而生? 现在知道,为什么java在游戏上插不上足,这样根本是不行的。不用对象,又难以区分数据库为空的数据,真是进退两难。
为什么java不在新版本上来个新架构啊,这样下去只有一条:死.........
算这个有意义吗?你认为你算的准确吗?
你以为java就只吃了你列出的那些内存吗?
得了,你不如去搞C吧,内存你自己控制,想怎么搞怎么搞
哈哈~
喜欢java总希望会改正 从1.3,1,4,1.5,1.6都是这样,我急了。为什么不能再好些。
我拿国外的一个程序测试的(1.5java内部已经可以测试了:java.lang.instrument.Instrumentation.getObjectSize(o)).
测试用的外国程序:
import java.util.ArrayList;
import java.math.BigDecimal;/**
* @author guishuanglin 2008-12-2 原程序作者:Vladimir Roubtsov
*
*/
public class Sizeof {
public static void main(String[] args) throws Exception {
// Warm up all classes/methods we will use
runGC();
usedMemory();
// Array to keep strong references to allocated objects
final int count = 100000;
Object[] objects = new Object[count]; long heap1 = 0;
// Allocate count+1 objects, discard the first one
for (int i = -1; i < count; ++i) {
Object object = null; // Instantiate your data here and assign it to object // object = new Object();
// object = new Integer (i);
// object = new Long (i);
// object = new String ();
// object = new byte [128][1];
// object = new Float(1);
// object = new Double(1);
// object = new BigDecimal(1);
object = new String(); if (i >= 0)
objects[i] = object;
else {
object = null; // Discard the warm up object
runGC();
heap1 = usedMemory(); // Take a before heap snapshot
}
}
runGC();
long heap2 = usedMemory(); // Take an after heap snapshot: final int size = Math.round(((float) (heap2 - heap1)) / count);
System.out.println("'before' heap: " + heap1 + ", 'after' heap: "
+ heap2);
System.out.println("heap delta: " + (heap2 - heap1) + ", {"
+ objects[0].getClass() + "} size = " + size + " bytes");
for (int i = 0; i < count; ++i)
objects[i] = null;
objects = null;
} private static void runGC() throws Exception {
// It helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r)
_runGC();
} private static void _runGC() throws Exception {
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 500); ++i) {
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield(); usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
} private static long usedMemory() {
return s_runtime.totalMemory() - s_runtime.freeMemory();
} private static final Runtime s_runtime = Runtime.getRuntime();
} // End of class
本来用 byte 只需要 100M,如果用 Byte就要 1.6G
(你有多少米?内存地址能搞多大?32? 64?)
本来用 int 只需要 400M,如果用 Integer就要 1.6G如果大系统连操作系统都支持不了多大的内存,现在我们的系统日产数据: 300多万条(20多列),内存数据放得太多,服务器受不了。客户已经把内存加到 4G了。
只要你愿意把1 个方法 public void h(Number arg),换成 8个方法来写。
public void h(byte arg)
public void h(short arg)
……
当涉及到范型的时候,本来一个类就实现的设计,换成8个类来写。
....你产生了那么多数据,难道全部保存到内存中,也太强了吧
是对象,对象就有属性和方法,怎么会是指针+数据长度.........再说了
你拿一个对象去和基本类型比内存占用,有意义吗?面向对象编程的目的是什么??
就是啊 sun公司那么多高手都没觉得有必要该 楼主咋这么激动啊?
谈的与你的相法不一个问题。看清题。
http://topic.csdn.net/u/20081202/15/20ba8be0-04c7-4e54-bdd9-d2f6b3c1f413.html?seed=53448279
1,我不是说java比别人差,也没有针对java的开发者,请大家就这个问题发表意见,java这样做是否可取.2, 上面的数据我不敢有半点差错,都是经过详细测试取得的,并且在jdk1.6 也提供了方法可以测试,大家可试试。3, 做为java的开发者,我从2001年开始做开发,并不是什么新手,PB,delphi,vb,GX,Magic,java(20042002年开始),.net(2002年开始),在java方面,一直追求高性能的框架设计。
同时在j2ee,ejb,ejb3.0,hibernate,ibatis,jni,spring,web service方面,还算是个老手。并且经常学习新的东西(这也是我一直从2001年开始一直在csdn里的原因)。
所以没不会平白无故的说java不好,我只是觉得java在这方面应当可以做得更好,因为目前的框架还是沿用老式的体系与设计,而.net却不断进步,我是急啊。
4, 请大家只说价问题,不需要对人,再者,大家如果需要更深入JVM也需要这方面知识,
做为一个java开发者我认为:要指出并知道,自己喜欢的东西有什么问题,这样才能更好的开发出好系统。
喜欢它宠爱它,但不要过份的宠坏它。
所以java是知道这个问题,问题是改动太大,影响到根本的体系了。
大家可以在1.5测试:
Long a = 2L;
Long b = 2L;
System.out.println(a == b);
//结果为ture
两个对象的引用是一样的。
但是你测试:
Long c = 1000L;
Long d = 1000L;
看看?相引用一样吗?但是这种改变远远不能解决根本问题。只能是1.5速度快点点。
浪费太多。
/**
*
*/
package test;/**
* @author - yy
* @time - Dec 3, 2008 10:58:15 AM
*/
public final class TestObject { // 测试对象
// private boolean b1; 如果类里面不到8个(含8个)boolean ,TestObject 占内存是16 bytes;
// private boolean b2; 9-16个boolean,TestObject 占内存是24 bytes; 以此类推
// private boolean b3;
// private boolean b4;
// private boolean b5;
// private boolean b6;
// private boolean b7;
// private boolean b8;
// private boolean b9;
// int i1; 如果类里面不到2个(含2个)int ,TestObject 占内存是16 bytes;
// int i2; 2-4个int,TestObject 占内存是24 bytes; 以此类推
// int i3;
// long L1; 多一个long就增加8bytes
// long L2;// String的字段有
// char value[]=new char[0]; // 8bytes
// int offset; \
// int count; | 8bytes
// int hash; /
// long serialVersionUID = -6849794470754667710L; // 8bytes
// ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];// 8bytes
// 加上自身的8bytes
// 正好40bytes// 其他类型的类似
// 应该可以解释了吧
}
同样:面向对象也不是为了节省系统开销而存在的.同时,内存的占用与释放不但来自于底层结构,真正重要的还是项目设计.
如同你要导入2000万条记录一样,在一个事物里控制,就是用汇编来写代码,内存也是不够的.另外,包装类的内存占用计算貌似是错误的,它比你想象中更大,严格遵守了Java类的标准,有自己的属性和行为.
而BigDecimal类有可能是最大的(这个没计算).
比如说为什么String占用了40 bytes;ps: 另外上面的String的我也解释错了// String的字段有
// char value[]=new char[0]; // 16bytes
// int offset; \ 2个共用 8bytes
// int count; /
// int hash; // 8bytes
// long serialVersionUID = -6849794470754667710L; // 类属性不算,因为共用一个
// ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; // 类属性不算,因为共用一个
// 加上自身的8bytes
// 正好40bytes
value属性,如果该byte值小于在-127-128之间,直接共享byte常量池中的值.否则占用4字节
byteValue()方法,不知道它有多大...两条机器码长度,8个字节以内?....天知道...
shortValue()方法,不知道它有多大...
intValue()方法,不知道它有多大...
longValue()方法,不知道它有多大...
floatValue()方法,不知道它有多大...
doubleValue()方法,不知道它有多大...
toString()方法,不知道它有多大...
hashCode()方法,不知道它有多大...
equals(xxx)方法,不知道它有多大...
compareTo(xxx)方法,不知道它有多大...构造方法和静态方法伴随JVM同步加载,所有Byte实例共享,应该不计算在内喵~~`
它统计的是当前栈的总消耗.gc的调用同样是不可控制的,
不过看楼主的运行效果貌似回收很及时的样子,
也许是因为程序短小的缘故喵???
二、关于数组大小的问题,本身是可以增加大小的。
1.采用固定大小的办法是为了提高性能,这个应该都明白。那么关于这个大小是多少的问题,太小了,频繁增加性能反而降低,太大了又不能起到提高性能的作用。这个平衡点,我觉得sun找得还可以。
2.如果只在需要的时候给内存,则需要另给内存保留指针,该指针指向新增元素地址。频繁增加,不但更占用内存,而且降低性能。引伸出的问题是实际是不是需要频繁增加的呢,我觉得是的,尤其是一些高级类里面,不断地要掉父类构造和释放方法时。
总结、短时间内不会改变,即使改变也是增大。减小几乎不可能。
象Integer,Long包装类,是只保存被包装的数据。方法是另一回事。
如果这样的基础还不知道,建议同志们看<<龙书>>后再反对我的问题。回:likgui
java 设计有问题,这与回到机器时代没有相关联,是两回事吧,这里并没有说与其它语言的差别.
说的是java本身出现的设计问题。
另外不认为Java有多牛,每个语言都有自己优势的地方,在某些方面Java也是废材!
但是假如硬件是越来越贵了,那java该怎么办?
楼主的心情也是可以理解的,大家无非都是在担心java的发展嘛
希望大家讨论不要带情绪。大家都是在java这条路上发展的,是属于同一个方向,都是同一条船上的,不要为这些事争得面红耳赤。我想发表一下自己的看法:
1.楼主的那个项目看起来规模蛮大,但是不管怎么说,楼主项目的设计是有问题的;
而且,一个服务器4g的内存,也不奇怪。客户埋怨产品不好,从古至今,一直都是存在的,
我还想用1M的内存去跑网游呢,呵呵,难道客户那边的反馈就一定是客观的吗?
2.楼主的担心也不无道理。不过,我想我们作为开发者,还是应该首先从自己的代码入手。至于jvm,jdk,还是让sun那帮人忙活吧,除非你能搞出自己的更有效的产品出来。
那你就不能用C++做啊?看你这么强, 用C也行啊。 如果现有项目是java, 可以使用JNI吧?
既然都用那么多的JNI了,干脆就不再用Java了.
而且我想在这次技术大会,有人会提出java其它核心错误设计,不信大家可以等待。
当然不一定是我说的问题,可能是java更严重的设计问题。
int,char占用差不多。。你要修改基础类,支持你,等待你的喜讯。内存地址总线查的时候就以一个Byte为准。
lz说的那些基础数据什么的看着确实占内存不少,但一个设计好的方法里面要用到多少呢?即使是for循环,内部的变量在一个循环结束后就会把内存释放了吧?循环外部你能定义多少变量、对象呢?如果你一个方法体写了1M+,定义了N*N的变量、对象,那我无语了,,,多少内存也不够用的啊,,,
你有经历过用c写webservie的经历吗?那时你会体会到用java是多么美好。
在一个系统很大时需要缓存数据,比如:用户,系统配置,字典值等等,单用户现在已经达到1.35亿。用缓存来增加响应能力。
减少对数据库的冲击。这些变化很少的数据,没必要不断查询数据库。
再者使用一些工具,象hib之类也会有部分缓存。
java在处理一写基本类型是,都是采用的unicode编码,目的是让只要运行在jvm上的程序都是世界统一的,不论任何平台,在上层语言上都是统一的.然后sun在机器语言这一层次上编写出各种平台的jvm.
其实sun公司是非常有远见的,大家想想,所着用java的人越来越多,我们在硬件上会不会跟着软件来设计.而不用在让jvm运行在其他平台之上.
微软为什么要推出.net平台?就是为了与java强市场吗.但是个人觉得.net做的仅仅是让一些语言写出的程序在汇编这一层统一起来,我觉得从策略上远比不上sun公司
记得Sun有明确说明包装类和普通类在JVM上保持一致,实例方法在JVM的堆里需要单独划分,如果我理解错了,还麻烦求一个出处喵~``不过这个跑题了吧,楼主提出的问题不归属底层设计喵~`
面向对象(包装类)的开销必然比面向过程(基础类型)更大,它以更大的消耗为编码的逻辑服务.
就像现在的面向事物或者面向插件的开发,执行效率必然有更大的消耗----因为它出来的初衷节省的就不是内存.如果公司里同时有Java和C++两个部门.
也许就会经常听C++朋友们抱怨:我们C++的被分去一个糟糕的项目,那实在太坏了-----C++起比Java,要做烂尾可是真彻底,真容易.毕竟,我们有不同的关注重点,和不同的烦恼喵~!