结果体重一个enummysql 枚举 enum占的内存长度是多少

Android 中的 Enum 到底占多少内存?该如何用?
来源:open开发经验库
听说过一些论调,Enum 不该用啊,占用了很大的 dex 文件,占用很多内存。而到底确切占用了多少内存,没说。本文分析了枚举所占用的精确的内存大小,方便大家权衡选择,希望对大家有帮助。
关于 Enum 的使用
Enum 需要占用较大的内存,如果对内存敏感,请尽量少使用 Enum,换用做静态常量。
Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.
关于具体要占用多少内存呢?说得比较模糊。
内存占用对比
在 《》一文中, 介绍过如何衡量对象的大小,这个文章非常详细,建议大家看看 ,现举例说明。
public enum MonthEnum {
// 4 bytes
// -& 87 bytes
// 4 bytes
88 bytes
// 生成的数组 24 + 4 + 4
// MonthEnum[] values
public class MonthConst {
// 4 bytes
public static final int JANUARY = 1;
// 4 bytes
public static final int FEBRUARY = 2;
public class UseMonth {
// 4 bytes
private int mMonth = MonthConst.JANUARY;
// 4 bytes
private MonthEnum mMonthEnum = MonthEnum.JANUARY;
我们不考虑 MonthEnum 和 MonthConst 他们对于 dex 大小的影响,这个没什么意义,几十个 Enum 占用的大小,也不及一张图片。
我们要对比的是 UseMonth 中这两种写法所占用的内存大小在 Dalvik 虚拟机下的区别。
在 UseMonth 中,他们一个是 int 类型,一个是对象引用,都是 4 字节,没有区别。
我们对比的大小,指的是对象本身的大小加上对象成员指向的其他对象大小,即 shadow heap + maintain heap。
MonthEnum 对于一个 MonthEnum, JANUARY 和 FEBRUARY 是两个指向 MonthEnum 实例的引用。他们分别占用 4 个字节。 他们指向的实例对象还要占用额外的内存。 我们看看 enum 的定义: 
class Enum {
private final S
priva
作为 Enum 成员变量 name(对象引用) 和 ordinal(int) 他们各占用 4 个字节,该对象实例占用:12 + 4 + 4 = 20 bytes,对齐之后是 24 字节。 但是,name 是字符串,空字符串对象本身就是 32 字节,加上其中的字符数组最少也会占据 24 个字节, 对字符串加字符数组最少会占据 56 个字节。故一个 Enum 实例,最少 80 个字节。 MonthEnum.JANUARY,含有 7 个字符,87 个字节;MonthEnum.FEBRUARY,8 个字符,88 个字节。
会有一个 values() 数组,两个对象引用的数组占用: 24 + 4 + 4 = 32 bytes。 总计是: 4 + 4 + 87 + 88 + 32
MonthConst JANUARY 和 FEBRUARY 各占 4 个字节。共计 8 个字节。 总计是: 4 + 4
上面我们对比了只具有两个枚举值的枚举和常量,如果数量更多的话,枚举的命名更长的话,这个差距会更大。
文档所说的两倍
所以实际占用的内存,并非
所说的两倍左右。
假设有 n 个枚举值,仅仅考虑枚举类,静态占用的内存,n 个引用 + n 个数组 + 24 空数组长度: 8n + 24。
而对于 n 个值的常量,则有 4n 字节。当 n 很大时,这样的关系是两倍,但是枚举引用所指向的内存(retained heap)没有考虑进来。
该用不该用?
You should strictly avoid using enums on Android.
枚举有其其他的特性,如果你需要这些特性,比如:非连续数值的判断,重载等时,可以用。
另外,内存用量也并非那么地可怕,枚举带来的编码的便捷,代码可读性的提升也是很大的利好。
看到这里,你应该了解了所有的细节了,是否该用,各位自己权衡。
更多的讨论,可以看这里: 。
如果更好地使用常量
如果应用确实对内存用量敏感,或者你就是追求极致,可用常量来代替枚举。
常量一般会和 Bit Mask 结合起来用,这样可以极致地减少了内存使用,同时使代码有较好的可读性。
下一篇文章会提到。
来自:http://www.liaohuqiu.net/cn/posts/android-enum-memory-usage/
免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动专为枚举类设计的集合类EnumSet - 实践求真知 - ITeye技术网站
博客分类:
一 集合类EnumSet概述
EnumSet是一个专为枚举类设计的集合类,EnumSet中所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类的定义顺序来决定集合元素的顺序。
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用内存很小,而且运行效率很好。尤其是当进行批量操作(如调用containsAll 和 retainAll方法)时,如果其参数也是EnumSet集合,则该批量操作的执行速度也非常快。
EnumSet集合不允许加入null元素。如果试图插入null元素,EnumSet将抛出 NullPointerException异常。如果仅仅只是试图测试是否出现null元素、或删除null元素都不会抛出异常,只是删除操作将返回false,因为没有任何null元素被删除。
二 EnumSet类的常规应用
1 代码示例
import java.util.*;
enum Season
SPRING,SUMMER,FALL,WINTER
public class EnumSetTest
public static void main(String[] args)
// 创建一个EnumSet集合,集合元素就是Season枚举类的全部枚举值
EnumSet es1 = EnumSet.allOf(Season.class);
System.out.println(es1); // 输出[SPRING,SUMMER,FALL,WINTER]
// 创建一个EnumSet空集合,指定其集合元素是Season类的枚举值。
EnumSet es2 = EnumSet.noneOf(Season.class);
System.out.println(es2); // 输出[]
// 手动添加两个元素
es2.add(Season.WINTER);
es2.add(Season.SPRING);
System.out.println(es2); // 输出[SPRING,WINTER]
// 以指定枚举值创建EnumSet集合
EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER);
System.out.println(es3); // 输出[SUMMER,WINTER]
EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER);
System.out.println(es4); // 输出[SUMMER,FALL,WINTER]
// 新创建的EnumSet集合的元素和es4集合的元素有相同类型,
// es5的集合元素 + es4集合元素 = Season枚举类的全部枚举值
EnumSet es5 = plementOf(es4);
System.out.println(es5); // 输出[SPRING]
2 运行结果
[SPRING, SUMMER, FALL, WINTER][][SPRING, WINTER][SUMMER, WINTER][SUMMER, FALL, WINTER][SPRING]
3 代码说明
此代码示范了如何使用EnumSet来保存枚举类的多个枚举值。
三 EnumSet类的错误使用
1 代码示例
import java.util.*;
enum Season
SPRING,SUMMER,FALL,WINTER
public class EnumSetTest2
public static void main(String[] args)
Collection c = new HashSet();
c.clear();
c.add(Season.FALL);
c.add(Season.SPRING);
// 复制Collection集合中所有元素来创建EnumSet集合
EnumSet enumSet = EnumSet.copyOf(c);
System.out.println(enumSet); // 输出[SPRING,FALL]
c.add("Java");
c.add("Linux");
// 下面代码出现异常:因为c集合里的元素不是全部都为枚举值
enumSet = EnumSet.copyOf(c);
System.out.println(enumSet);
2 运行结果
[SPRING, FALL]Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Enum
at java.util.EnumSet.copyOf(Unknown Source)
at EnumSetTest2.main(EnumSetTest2.java:21)
3 代码说明
当试图复制一个Collection集合里的元素来创建EnumSet集合时,必须保证Collection集合里的所有元素都是同一个枚举类的枚举值。
浏览: 47244 次
来自: 西安
好文,弱弱的问一句,跟tcpflow的应用场景有什么不同
xiaofanac66 写道我认为最关键的是JAVA fina ...
我认为最关键的是JAVA final 指令重拍
构造方法逃逸 ...
不还是被射死了吗。是智商低吧,还狼性思维
这个比如不贴切吧,狮子笼不是最危险的哟2012年7月 C/C++大版内专家分月排行榜第二2012年6月 C/C++大版内专家分月排行榜第二
2013年6月 Linux/Unix社区大版内专家分月排行榜第二2013年5月 Linux/Unix社区大版内专家分月排行榜第二2013年3月 Linux/Unix社区大版内专家分月排行榜第二2013年1月 Linux/Unix社区大版内专家分月排行榜第二2012年12月 Linux/Unix社区大版内专家分月排行榜第二2012年8月 Linux/Unix社区大版内专家分月排行榜第二2011年12月 Linux/Unix社区大版内专家分月排行榜第二2011年10月 C/C++大版内专家分月排行榜第二2011年10月 Linux/Unix社区大版内专家分月排行榜第二
2012年6月 C/C++大版内专家分月排行榜第三2012年6月 PHP大版内专家分月排行榜第三2012年5月 C/C++大版内专家分月排行榜第三2012年3月 Linux/Unix社区大版内专家分月排行榜第三2012年2月 Linux/Unix社区大版内专家分月排行榜第三2011年11月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。君,已阅读到文档的结尾了呢~~
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
A第十章 结构联合与枚举
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口C++11 之 scoped enum_Linux编程_Linux公社-Linux系统门户网站
你好,游客
C++11 之 scoped enum
来源:Linux社区&
作者:xinxue
C++11 枚举类型是&域化的& (scoped enum),相比 C++98 枚举类型的&非域化& (unscoped enum),具有如下优点:
1& 命名空间污染&
一般来说,声明在花括号内的名字,其可见性限制在由花括号定义的作用域内,但是非域化枚举 (unscoped enum) 却是例外
enum Color { black, white, red }; // black, white, red are in same scope as Color
auto white = false; // error! white already declared in this scope
& & C++11 域化枚举 (scoped enum),关键字为 enum class,可视为一个 "class",故能防止&命名空间污染& (namespace pollution)
enum class Color { black, white, red }; // black, white, red are scoped to Color
auto white = false; // fine, no other "white" in scope
Color c = white; // error! no enumerator named "white" is in this scope
Color c = Color::white; // fineauto c = Color::white; // also fine
2& 强类型枚举
& 非域化的枚举成员,可以隐式的转换为广义整型 (integral types),如下所示:
enum Color { black, white, red }; // unscoped enum
std::vector&std::size_t& primeFactors(std::size_t x); // func. returning prime factors of x
if (c & 14.5) // compare Color to double (!)
auto factors = primeFactors(c); // compute prime factors of a Color (!)
& 域化的枚举成员,却不可以隐式的转换为广义整型
enum class Color { black, white, red }; // enum is now scoped
Color c = Color:: // as before, but with scope qualifier
if (c & 14.5)
// error! can't compare Color and double
auto factors = primeFactors(c); // error! can't pass Color to function expecting std::size_t
& 正确的方式是使用 C++ 的类型转换符 (cast)
if (static_cast&double&(c) & 14.5)
// odd code, but it's valid
auto factors = primeFactors(static_cast&std::size_t&(c)); // suspect, but it compiles
3& 前置声明
域化枚举支持前置声明 (forward-declared),也即可以不用初始化枚举成员而声明一个枚举类型
enum class C
3.1 新增枚举成员
& 非域化枚举(unscoped enum) 在声明时,编译器会选择占用内存最小的一种潜在类型 (underlying types),来代表每一个枚举成员
enum Color { black, white, red };
// compiler may choose char type
& 下面的例子中,编译器可能会选择更大的能够包含 0 ~ 0xFFFFFFFF 范围的潜在类型
enum Status {
failed = 1,
incomplete = 100,
corrupt = 200,
indeterminate = 0xFFFFFFFF
& 非前置声明的缺点在于,当增加一个新的枚举成员时 (如下例的 audited ),整个系统将会被重新编译一遍,即使只有一个很简单的函数使用了新的枚举成员 (audited)
enum Status {
failed = 1,
incomplete = 100,
corrupt = 200,
audited = 500,
indeterminate = 0xFFFFFFFF
& 而使用前置声明,当新增枚举成员时,包含这些声明的头文件并不需要重新编译,源文件则根据新枚举成员的使用情况来决定是否重新编译
& 如下例,Status 中新增枚举成员 audited,如果函数 continuteProcesing 没有使用 audited,则函数 continuteProcesing 的实现并不需要重新编译
enum class S // forward declaration
void continueProcessing(Status s); // use of fwd-declared enum
3.2 潜在类型
& 域化枚举的潜在类型 (underlying type),缺省为 int 型,当然也可以自行定义潜在类型。不管哪种方式,编译器都会预先知道枚举成员的大小
enum class S // underlying type is int
enum class Status: std::uint32_t; // underlying type for Status is std::uint32_t (from &cstdint&)
enum class Status: std::uint32_t
// specify underlying type on enum's definition{
failed = 1,
incomplete = 100,
corrupt = 200,
audited = 500,
indeterminate = 0xFFFFFFFF
4& std::tuple
& 一般而言,使用 C++11 域化枚举 (scoped enum) 是比较好的选择,但 C++98 非域化枚举 (unscoped enum) 也并非一无是处
4.1& 非域化枚举
& 当涉及到 std::tuple 时,使用 C++98 非域化枚举反而会有优势,如下例所示
& 假定一个社交网站中,每一位用户,都使用一种模板类型 - 元组 (tuple) 来包含名字、邮箱、声望值 (name, email, reputation value)
using UserInfo = std::tuple&std::string, std::string, std::size_t& ; // type alias
& 当以下代码在另一个不同的源文件里时 (source file),很有可能忘了元组 (tuple) 的第一个成员到底是名字还是邮箱 (name or email)
UserInfo uI // object of tuple type
auto val = std::get&1&(uInfo); // get value of field 1
& 但是,使用非域化枚举 (unscoped enum),可以不用担心忘记了元组内的成员顺序
enum UserInfoFields { uiName, uiEmail, uiReputation };
UserInfo uI // as before
auto val = std::get&uiEmail&(uInfo); // get value of email field
4.2& 域化枚举&
& 上例中,假如使用域化枚举 (scoped enum),则会用到类型转换,看起来比较繁琐
enum class UserInfoFields { uiName, uiEmail, uiReputation };
UserInfo uI // as before
auto val = std::get&static_cast&std::size_t&(UserInfoFields::uiEmail)&(uInfo);
& 可以使用一个模板函数,将枚举成员 UserInfoFields::uiEmail 和 std::size_t 类型联系起来
template&typename E&
constexpr typename std::underlying_type&E&::type toUType(E enumerator) noexcept
return static_cast&typename std::underlying_type&E&::type&(enumerator);
&这样,便可以稍微缩减了代码的复杂度。但是相比于非域化枚举,看起来还是有些繁琐
auto val = std::get&toUType(UserInfoFields::uiEmail)&(uInfo);
1)& C++98 枚举类型是&非域化的&;而C++11 枚举类型是&域化的&,枚举成员只在域内可见
2)& 域化枚举的缺省潜在类型 (underlying type) 是 int 型,而非域化枚举没有缺省潜在类型
3)& 域化枚举一般总是前置声明,而非域化枚举只有在指定了潜在类型时才可以是前置声明
参考资料:
& &Effective Modern C++& Item 10
本文永久更新链接地址:
相关资讯 & & &
& (04月28日)
& (12/20/:31)
& (05月11日)
& (12/20/:06)
& (12/20/:38)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款}

我要回帖

更多关于 枚举enum 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信