【dualvol 源码】【乱世天下源码】【动态换肤源码】jvmnewarray源码

时间:2024-11-23 13:17:52 编辑:mybatis框架源码分析 来源:仿服务市场 源码

1.如何计算java对象占用的内存
2.scala manifest和classmanifest的区别
3.java中两个字符串的内存地址相同

jvmnewarray源码

如何计算java对象占用的内存

       Java有一个很好的地方就是java的垃圾收集机制,这个机制集成于jvm的,对程序员来说是隐藏且不透明的。这种情况下,如何得到某个对象消耗的内存呢?

       ã€€ã€€

       ã€€ã€€ã€€ã€€æ›¾ç»çœ‹åˆ°è¿‡æœ‰äººç”¨ä»¥ä¸‹æ–¹æ³•æ¥è®¡ç®—:在生成该object的前后都调用java.lang.Runtime.freeMemory()方法,然后看两者之差即为该object消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€è¿™ç§æ–¹æ³•çš„代码是:

       ã€€ã€€

       ã€€ã€€long totalMem = java.lang.Runtime.freeMemory();

       ã€€ã€€Object myBigObject = null;

       ã€€ã€€System.out.println("You just got rid of " + totalMem

       ã€€ã€€ - java.lang.Runtime.freeMemory());

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€ã€€ã€€è¿™ç§æƒ³æ³•æ˜¯å¯¹çš„,但是实际上,jvm的freememory往往不能正确反应实际的free

        memory。比如在jvm要进行垃圾收集的时候,free

       memory就会缩小。而如果决定垃圾收集的时间发生在该object生成之后,而在第二次调用java.lang.Runtime.freeMemory()之前,那么就会错误地增加该object消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€åœ¨java专家By

        Tony Sintes的文章"Discover how much memory an object consumes "

       é‡Œé¢æåˆ°äº†åº”该用Runtime.getRuntime().totalMemory();并且计算两次之差来得到消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€By Tony Sintes的源代码:

       ã€€ã€€

       ã€€ã€€public class Memory {

       ã€€ã€€ private final static int _SIZE = ;

       ã€€ã€€ public static void main( String [] args )

       ã€€ã€€ throws Exception {

       ã€€ã€€ Object[] array = new Object[_SIZE];

       ã€€ã€€ Runtime.getRuntime().gc();

       ã€€ã€€ long start = Runtime.getRuntime().totalMemory();

       ã€€ã€€ for (int i = 0; i < _SIZE; i++) {

       ã€€ã€€ array[i] = new Object();

       ã€€ã€€ }

       ã€€ã€€ Runtime.getRuntime().gc();

       ã€€ã€€ long end = Runtime.getRuntime().totalMemory();

       ã€€ã€€ long difference = ( start - end ) / _SIZE;

       ã€€ã€€ System.out.println( difference + " bytes used

       ã€€ã€€ per object on average" );

       ã€€ã€€ }

       ã€€ã€€}

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€ã€€ã€€å®žé™…上,这种方法基本上正确了,但是By Tony Sintes疏忽了一点,就是仅仅Runtime.getRuntime().gc();并不能真正完成垃圾收集,也就是说实际上jvm的内存此时并不是稳定的。

       ã€€ã€€

       ã€€ã€€ã€€ã€€æ‰€ä»¥ï¼Œåªæœ‰å½“内存不再发生大的变动,或者说已经稳定,我们才可能说垃圾收集已经完成。

       ã€€ã€€

       ã€€ã€€ã€€ã€€å¦‚何才能真正确保基本完成了jvm的垃圾收集呢?实现这个功能的代码如下:

       ã€€ã€€

       ã€€ã€€private static final Runtime s_runtime =

       ã€€ã€€ Runtime.getRuntime ();

       ã€€ã€€private static long usedMemory ()

       ã€€ã€€ {

       ã€€ã€€ return s_runtime.totalMemory () -

       ã€€ã€€ s_runtime.freeMemory ();

       ã€€ã€€ }

       ã€€ã€€private static void runGC () throws Exception

       ã€€ã€€ {

       ã€€ã€€long usedMem1 = usedMemory (),dualvol 源码 usedMem2 = Long.MAX_value;

       ã€€ã€€for (int i = 0; (usedMem1 < usedMem2) && (i < ); ++ i)

       ã€€ã€€ {

       ã€€ã€€ s_runtime.runFinalization ();

       ã€€ã€€ s_runtime.gc ();

       ã€€ã€€ Thread.currentThread ().yield ();

       ã€€ã€€ usedMem2 = usedMem1;

       ã€€ã€€ usedMem1 = usedMemory ();

       ã€€ã€€ }

       ã€€ã€€ }

scala manifest和classmanifest的区别

       Manifest是scala2.8引入的一个特质,用于编译器在运行时也能获取泛型类型的信息。在JVM上,泛型参数类型T在运行时是被“擦拭”掉的,编译器把T当作Object来对待,所以T的具体信息是无法得到的;为了使得在运行时得到T的信息,scala需要额外通过Manifest来存储T的信息,并作为参数用在方法的运行时上下文。

       def test[T] (x:T, m:Manifest[T]) { ... }

       æœ‰äº†Manifest[T]这个记录T类型信息的参数m,在运行时就可以根据m来更准确的判断T了。但如果每个方法都这么写,让方法的调用者要额外传入m参数,非常不友好,且对方法的设计是一道伤疤。好在scala中有隐式转换、隐式参数的功能,在这个地方可以用隐式参数来减轻调用者的麻烦。

       èŽ·å–class manifests的两种基本方式:

        1 def classOf[T <: Any](implicit m: scala.reflect.Manifest[T]): Class[T] = m.erasure.asInstanceOf[Class[Tï¼½

        通过implicit m: scala.reflect.Manifest[T]声明一个隐式参数,这样scala编译器能在编译时提供T的类型信息了

        2 def classOf[T <: Any : Manifest] : Class[T] = manifest[T].erasure.asInstanceOf[Class[Tï¼½

        其中 T <: Any : Manifest,拆分成两部分来看

        T <: Any

        T 是Any的子类型(即可以是任意基本类型scala.AnyVal 和引用类型 scala.AnyRef)

        T : Manifest 相当于对classOf 方法currying

        隐式增加参数列表如下:(implicit evidence$1: Manifest[T]),

        通过manifest[T] 方法即可获取Manifest实例

        可见形式1 和形式2实质是一样的。

       åº”用:

        1最常见的是获取类型参数的Class,形如someMethod[Type]

        如akka中源码: def actorOf[T <: Actor : Manifest]: ActorRef = actorOf(manifest[T].erasure.asInstanceOf[Class[_ <: Actorï¼½)

        class Worker extends Actor {

        def receive = {

        case Work(start, nrOfElements) =>

        self reply Result(calculatePiFor(start, nrOfElements)) // perform the work

        }

        }

        就可以如此使用了: val workerActorRef = actorOf[Worker]

        2 编程方式创建范型数组

        def evenElems[T: ClassManifest](xs: Vector[T]): Array[T] = {

        val arr = new Array[T]((xs.length + 1) / 2)

        for (i <- 0 until xs.length by 2)

        arr(i / 2) = xs(i)

        arr

        }

        scala> evenElems(Vector("a","b","c"))

        res: Array[java.lang.String] = Array(a, c)

java中两个字符串的内存地址相同

       String s1 = new String("I am a student"); 这里 你声明了一个引用 s1\x0d\指向的是 new String("I am a student"); 这个字符串\x0d\String s4 = s1; 这里 你又声明一个引用 指向s1的引用 也就是new String("I am a student"); \x0d\if(s1 == s4) { \x0d\System.out.println("这两个字符串的内存位置相同");\x0d\}\x0d\上面还是相等的\x0d\但是 s4 = s4.replace('a', 'A');\x0d\s4.replace('a', 'A'); 生成了另一个 字符串 你要知道 String 是final类型的 所以\x0d\这个时候 即原来已经开辟了内存空间的 new String("I am a student"); 是不可能改变内容了的\x0d\这个时候 s4.replace('a', 'A'); 就另开辟了一个内存空间\x0d\ 而这个时候 你的S4指向s4.replace('a', 'A'); 而原来的s1还是指向 new String("I am a student"); \x0d\他们肯定不一样的呢