我有这两段虚拟代码(假设它们是用 Java 或 C# 编写的,所有变量都是本地的):
代码 1:
int a;
int b = 0;
for (int i = 1; i < 10 ; i++)
{
a = 10;
b += i;
// a lot of more code that doesn't involve assigning new values to "a"
}
代码 2:
int b = 0;
for (int i = 1; i < 10 ; i++)
{
int a = 10;
b += i;
// a lot of more code that doesn't involve assigning new values to "a"
}
乍一看,我会说这两个代码消耗相同数量的内存,但代码 1 的 CPU 效率更高,因为它只创建和分配变量 a 一次。
然后我读到垃圾收集器非常高效,以至于代码 2 的内存(和 CPU?)效率更高:将变量 a 保留在循环中使其属于 Gen0,所以它会是在变量 b 之前收集的垃圾。
因此,当与垃圾收集语言一起使用时,代码 2 的效率更高。我说得对吗?
最佳答案
几点:
int(和其他原语)从不在堆上分配。它们直接存在于线程堆栈上,“分配”和“释放”是指针的简单移动,并且发生一次(进入函数时,返回后立即发生),与范围无关。
经常访问的基元通常存储在寄存器中以提高速度,同样,无论作用域如何。
在您的情况下,a(可能还有 b,连同整个循环)将被“优化掉”,优化器足够聪明检测变量值发生变化但从未被读取的情况,并跳过冗余操作。或者,如果有代码实际查看 a,但不修改它,它可能会被优化器替换为常量值“10”,它将内联出现在任何地方a 被引用。
新对象(例如,如果你做了类似 String a = new String("foo") 而不是 int 的操作)总是分配在年轻代, 并且只有在他们在一些小的 Collection 中幸存下来之后才会被转移到老年代。这意味着,在大多数情况下,当一个对象在函数内部分配,并且从不从外部引用时,无论其确切范围如何,它都永远不会进入老一代,除非你的堆结构迫切需要调整。
正如评论中所指出的,有时 VM 可能会决定直接在老一代中分配一个大对象(这对 java 也是如此,而不仅仅是 .net),所以上面的观点只适用于大多数情况例,但不是总是。然而,对于这个问题,这没有任何区别,因为如果决定在老年代分配一个对象,无论如何它都是在不考虑其初始引用范围的情况下做出的。
从性能和内存的角度来看,您的两个代码段是相同的。但是从可读性的角度来看,在尽可能窄的范围内声明所有变量总是一个好主意。
关于java - 与垃圾收集语言一起使用时,哪种代码的 CPU/内存效率更高?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27865812/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的