静态和常量字段的内存消耗

6

我有一个类,其中有一个字符串字段。这个字符串字段是常量,并且将来会移动到资源文件中,但目前它仍然存在于我们的类中。现在的情况是,我正在创建超过100个这个类的对象。因此,我的问题是采用哪种方法可以消耗更少的内存,为什么?

  1. I should make my string variable static

    public class MyClass
    {
        public static string MyString = "My String";
    }
    
  2. I should make my string variable const

     public class MyClass
     {
        public const string MyString = "My String";
     }
    

3
现在的情况是我正在创建超过一百个这个类的对象。但是,无论您创建多少个MyClass对象实例, MyString 属性只会分配一次。这是使用static的一个优点。 - Kevin Gosse
如果您选择第一种方法,请考虑添加“readonly”关键字,参见https://dev59.com/AWgu5IYBdhLWcg3wbWo9。 - C.Evenhuis
4
我的问题是哪种方法会消耗更少的内存,为什么?你认为这很重要吗?你测量过差异吗?还是这只是一个假设性的问题? - CodeCaster
相关:static readonly vs const - Sergey Kalinichenko
6个回答

5

有一个区别。静态变量在动态内存空间中初始化,因此占用额外的内存空间,更不用说你需要可执行代码(额外的内存)来初始化它们和访问它们。

所有const数据都位于与可执行代码相同的内存空间中,即只读存储器(ROM),而静态数据则加载到动态内存中,您可能可以对其进行读写。现在是一个有趣的部分,在以前的回答中似乎被忽略了。静态数据占用动态内存空间,但需要额外的ROM空间,并且在最坏的情况下可能占用两倍的内存。考虑以下内容:

class StaticData
{
    static string s_static1 = "My string data";
}

class ConstData
{
    const string CONST1 = "My string data";
}

类StaticData有变量s_static1,它将占用动态内存空间的单个指针(通常为1个整数)。但是,它也必须被初始化,因此必须存在ROM代码来初始化它。字符串数据本身通常位于ROM空间中,因为字符串数据是不可变的,并且不会占用比常量更多的空间。

对于类ConstData,只需要ROM存储空间,因此在大多数情况下,这是最好的内存使用方式。

当考虑编译器如何使用数据时,情况变得更加有趣。除了字符串/字符数据外,常量通常直接在引用点处替换为代码。换句话说,常量值直接加载到寄存器或根据使用情况推送到堆栈中。对于静态变量,编译器必须通过附加代码(指针引用)从内存中读取该值,因此需要额外的ROM代码。

总之,静态代码将占用更多的内存,既占用额外的动态内存空间,又需要额外的可执行代码空间来反引用它。


1
我认为在内存方面不会有任何区别。两种方式都会消耗相同的内存。但是性能可能会有所不同 - constant 字段更好,因为我认为您不希望更改 MyString 的值,并且常量成员在编译时定义,无法在运行时更改。

我的错 - 编辑了答案 - 给出了关于内存和性能的意见 - Shumail
1
如果我有 class MyClass { public static readonly string Used = "short string"; public static readonly string NeverUsed = "one gigabyte string here!"; } 一旦我引用了 Used,运行时是否必须将巨大的 NeverUsed 字符串放入堆中?另一方面,如果 NeverUsed 是一个从未被使用的 public const,那么我不是会“节省”一些内存吗? - Jeppe Stig Nielsen

0

从内存角度来看,两种方式没有区别。无论哪种方式,如果字符串的值尚未存在于内存中,您都需要将其加载到内存中一次。至于字符串的性能方面,正如KooKiz所指出的那样,差异不会太大(对于值类型会有差异,但通常您不应该关心这种微观优化)。


1
由于字符串已经被内部化,我甚至不确定是否存在性能差异。 - Kevin Gosse

0

常量不会占用任何内存。它将在编译时被定义的值所替代。 而将成员定义为静态的则会根据数据类型占用内存。


2
字符串常量是不同的 - 它们确实会消耗一些内存来存储字符串的内容。 - Sergey Kalinichenko

0

这两个选项将使用相同的内存量。唯一的区别在于,第一个选项允许更改MyString的值,而第二个选项则不允许,这可能是您想要的。


-1
如果它是一个不变的常量,你应该在类外将其设为全局变量。
否则,如果它必须成为站点的一部分,请将其设置为静态 :)

在C#中不存在final这样的东西。 - Daniel Hilgarth
我的错 :P - 在C#中是const吗? - ddoor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接