精华内容
下载资源
问答
  • 2020-12-30 17:09:52

    一般衡量内存的性能,主要看内存的频率和这个频率下的时序,而cl值又是内存时序的一项很重要的参数,cl值原则上越小越好。 这两套内存,一套2800mhz cl16,频率占。。

    c14好,但是,如果频率一样,这点时序的差异是没有性能差距的,如果是3200c15,比2133c14性能反而好很多,频率是第一位的,然后才看时序。。

    内存时序 一种参数,一般存储在内存条的SPD上。2-2-2-8 4个数字的含义依次为:CAS Latency(简称CL值)内存CAS延迟时间,他是内存的重要参数之一,某些牌子的。。

    十栓和威刚两个8G条,都2133的,处理器I5-7400(不带K的那种),大概能。。

    内存超频是没有一定的值的,这和主板 cpu 内存本身体质全是有关的。一般来说2400频率的四代内存能稳定运行在2666频率上就很不错了。。

    11 11 11 30。

    内存时序高,会影响电脑的性能。越高,性能越差。 1,日常使用的性能,基本上没有感觉。用户体会不到。 2,玩游戏的时候,会有明显的区别,特别是FPS游戏,会有。。

    你好!这个需要看你是什么平台的,一般DDR4 2133频率2400频率2666频率内存条比较合适普通用户,如果会超频就可以选择8G DDR4 3000频率3200频率3600频率等等。。

    我667的内存原本时序5-5-5-15的,超频到800(外频300,内存比1:1.33), 。。

    对!时序越低越好,不过看频率而定,内存超频时时序就要拉大。DDR2的5-5-5-15都可以超频到800Mhz使用,800Mhz默认也是这个时序。DDR 默认时序3-3-3-9-2T(400。。

    不加压,高时序。。时序对性能影响极小。。

    至少2133频率,因为六代i3 i5 i7 e3内存控制支持是2133频率的。不能或不超频的cpu 平台 ,你上2133就可以了,想要超频能超频的就上更高频率的。还有就是,只要是主。。

    内存在标准的ddr400模式下的时序是3-4-4-8,哪位大侠能告诉我超频后内存。。

    你先把所有时序一格一格往下调,越小越好,如果你开不了机了就放电从来,直到能正常进系统,用SP2004跑内存,烤2~3天机是肯定要的,直到稳定下来为止 超频是简。。

    更多相关内容
  • 对于内存时序却关注的很少,其实内存时序也是内存的参数之一,但是对于内存时序的意思是什么?内存时序高低的好坏,估计没有几个用户了解。接下来就为大家分享有关于内存时序的一些基础知识。一、内存时序是什么意思...

    有不少电脑装机用户在选择电脑内存的时候都只关注内存品牌、内存容量以及内存频率而已。对于内存时序却关注的很少,其实内存时序也是内存的参数之一,但是对于内存时序的意思是什么?内存时序高低的好坏,估计没有几个用户了解。接下来就为大家分享有关于内存时序的一些基础知识。

    3bd737847055a4f1039ba95b15b592dc.png

    一、内存时序是什么意思?

    1529e8099a90794360a0adfb4474897e.png内存时序位置

    内存时序是描述同步动态随机存取存储器(SDRAM)性能的四个参数:CL、TRCD、TRP和TRAS,单位为时钟周期。它们通常被写为四个用破折号分隔开的数字,列如下图的16-18-18-36就代表这根内存的时序。(第四个参数经常被省略,而有时还会加入第五个参数:Command rate(命令速率),通常为2T或1T,也写作2N、1N。)

    在这四组数字之中,CL对内存性能的影响是最明显的,所以很多产品都会把内存CL指标在产品名上,一般DDR4内存的第一项数值在15左右浮动,但是DDR3内存的数值在5到11之间,而且后面三组数值也比DDR4内存要小,也就是说在相同的频率下,DDR3内存是要比DDR4更快的(小编并没有否定DDR4)。

    二、内存时序高好还是低好?

    内存时序参数指定了影响随机存储存储器速度的延迟时间。较低的数字通常意味着更快的性能,所以在内存频率相同的情况下,内存时序越小越好。

    一般情况下我们只需要看内存时序中的第一个数字,数字越小越好。

    三、内存挑选建议

    其实在选择内存的时候,内存时序并不是放在第一位去考虑的。而是先看容量,再看频率,最后再去对比内存时序。

    举个列子,有两根容量、频率相同的内存,它们的时序分别是16-18-18-38和17-17-17-39,那么前者的性能自然会更好一些。(当然也要考虑内存品牌的问题,宁愿选时序高的大品牌内存,也不要选时序低的山寨内存)

    如何查看电脑内存的时序?

    7ccde6ede1d9a2cbdece1dd2975d7685.png如何查看电脑内存的时序?

    我们可以下载一款CPU-Z软件,在内存的选项卡中查看CL、TRCD、TRP、TRAS的四个数值。

    一般情况下,内存时序都会标注在内存的铭牌上,如果内存上没有标注时序的话,我们也可以通过软件(CPU-Z)来查看内存时序。

    总结:内存时序该如何选择?

    如果内存容量,频率都相同的情况下,时序自然是越低越好。不过内存时序对于内存性能的影响非常小,除了跑分软件会体现出一点差异,在正常使用电脑的时候你根本感觉不出来的,与其在内存时序上纠结,还不如选个靠谱的品牌更为稳妥。

    举报/反馈

    展开全文
  • DDR内存时序设置详解

    2011-09-28 01:09:08
    DDR内存时序设置详解 DDR内存时序设置详解
  • 内存表是DolphinDB数据库的重要组成部分。内存表不仅可以直接用于存储数据,实现高速数据读写,而且可以缓存计算引擎的中间结果,加速计算过程。本教程主要介绍DolphinDB内存表的分类、使用场景以及各种内存表在数据...

    内存表是DolphinDB数据库的重要组成部分。内存表不仅可以直接用于存储数据,实现高速数据读写,而且可以缓存计算引擎的中间结果,加速计算过程。本教程主要介绍DolphinDB内存表的分类、使用场景以及各种内存表在数据操作以及表结构(schema)操作上的异同。


    1. 内存表类别

    根据不同的使用场景以及功能特点,DolphinDB内存表可以分为以下四种:

    • 常规内存表
    • 键值内存表
    • 流数据表
    • MVCC内存表


    1.1 常规内存表

    常规内存表是DolphinDB中最基础的表结构,支持增删改查等操作。SQL查询返回的结果通常存储在常规内存表中,等待进一步处理。

    • 创建

    使用table函数可创建常规内存表。table函数有两种用法:第一种用法是根据指定的schema(字段类型和字段名称)以及表容量(capacity)和初始行数(size)来生成;第二种用法是通过已有数据(矩阵,表,数组和元组)来生成一个表。

    使用第一种方法的好处是可以预先为表分配内存。当表中的记录数超过容量时,系统会自动扩充表的容量。扩充时系统首先会分配更大的内存空间(增加20%到100%不等),然后复制旧表到新的表,最后释放原来的内存。对于规模较大的表,扩容的成本会比较高。因此,如果我们可以事先预计表的行数,建议创建内存表时预先分配一个合理的容量。如果表的初始行数为0,系统会生成空表。如果初始行数不为0,系统会生成一个指定行数的表,表中各列的值都为默认值。例如:

    //创建一个空的常规内存表
    t=table(100:0,`sym`id`val,[SYMBOL,INT,INT])
    
    //创建一个10行的常规内存表
    t=table(100:10,`sym`id`val,[SYMBOL,INT,INT])
    select * from t
    
    sym id val
    --- -- ---
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  
        0  0  

    table函数也允许通过已有的数据来创建一个常规内存表。下例是通过多个数组来创建。

    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    t=table(sym,id,val)
    • 应用

    常规内存表是DolphinDB中应用最频繁的数据结构之一,仅次于数组。SQL语句的查询结果,分布式查询的中间结果都存储在常规内存表中。当系统内存不足时,该表并不会自动将数据溢出到磁盘,而是Out Of Memory异常。因此我们进行各种查询和计算时,要注意中间结果和最终结果的size。当某些中间结果不再需要时,请及时释放。关于常规内存表增删改查的各种用法,可以参考另一份教程内存分区表加载和操作


    1.2 键值内存表

    键值内存表是DolphinDB中支持主键的内存表。通过指定表中的一个或多个字段作为主键,可以唯一确定表中的记录。键值内存表支持增删改查等操作,但是主键值不允许更新。键值内存表通过哈希表来记录每一个键值对应的行号,因此对于基于键值的查找和更新具有非常高的效率。

    • 创建

    使用keyedTable函数可创建键值内存表。该函数与table函数非常类似,唯一不同之处是增加了一个参数指明键值列的名称。

    //创建空的键值内存表,主键由sym和id字段组成
    t=keyedTable(`sym`id,1:0,`sym`id`val,[SYMBOL,INT,INT])
    
    //使用向量创建键值内存表,主键由sym和id字段组成
    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    t=keyedTable(`sym`id,sym,id,val)
    注意:指定容量和初始大小创建键值内存表时,初始大小必须为0。

    我们也可以通过keyedTable函数将常规内存表转换为键值内存表。例如:

    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    tmp=table(sym, id, val)
    t=keyedTable(`sym`id, tmp)
    • 数据插入和更新的特点

    往键值内存表中添加新纪录时,系统会自动检查新记录的主键值。如果新记录中的主键值不存在于表中,那么往表中添加新的记录;如果新记录的主键值与已有记录的主键值重复时,会更新表中该主键值对应的记录。请看下面的例子。

    首先,往空的键值内存表中插入新记录,新记录中的主键值为AAPL, IBM和GOOG。

    t=keyedTable(`sym,1:0,`sym`datetime`price`qty,[SYMBOL,DATETIME,DOUBLE,DOUBLE]);
    insert into t values(`APPL`IBM`GOOG,2018.06.08T12:30:00 2018.06.08T12:30:00 2018.06.08T12:30:00,50.3 45.6 58.0,5200 4800 7800);
    t;
    
    sym  datetime            price qty 
    ---- ------------------- ----- ----
    APPL 2018.06.08T12:30:00 50.3  5200
    IBM  2018.06.08T12:30:00 45.6  4800
    GOOG 2018.06.08T12:30:00 58    7800

    再次往表中插入一批主键值为AAPL, IBM和GOOG的新记录。

    insert into t values(`APPL`IBM`GOOG,2018.06.08T12:30:01 2018.06.08T12:30:01 2018.06.08T12:30:01,65.8 45.2 78.6,5800 8700 4600);
    t;
    
    sym  datetime            price qty 
    ---- ------------------- ----- ----
    APPL 2018.06.08T12:30:01 65.8  5800
    IBM  2018.06.08T12:30:01 45.2  8700
    GOOG 2018.06.08T12:30:01 78.6  4600

    可以看到,表中记录条数没有增加,但是主键对应的记录已经更新。

    继续往表中插入一批新记录,新记录本身包含了重复的主键值MSFT。

    可以看到,表中有且仅有一条主键值为MSFT的记录。

    • 应用场景

    (1)键值表对单行的更新和查询有非常高的效率,是数据缓存的理想选择。与redis相比,DolphinDB中的键值内存表兼容SQL的所有操作,可以完成根据键值更新和查询以外的更为复杂的计算。

    (2)作为时间序列聚合引擎的输出表,实时更新输出表的结果。具体请参考教程使用DolphinDB计算K线

     


    1.3 流数据表

    流数据表顾名思义是为流数据设计的内存表,是流数据发布和订阅的媒介。流数据表具有天然的流表对偶性(Stream Table Duality),发布一条消息等价于往流数据表中插入一条记录,订阅消息等价于将流数据表中新到达的数据推向客户端应用。对流数据的查询和计算都可以通过SQL语句来完成。

    • 创建

    使用streamTable函数可创建流数据表。streamTable的用法和table函数完全相同。

    //创建空的流数据表
    t=streamTable(1:0,`sym`id`val,[SYMBOL,INT,INT])
    
    //使用向量创建流数据表
    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    t=streamTable(sym,id,val)

    我们也可以使用streamTable函数将常规内存表转换为流数据表。例如:

    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    tmp=table(sym, id, val)
    t=streamTable(tmp)

    流数据表也支持创建单个键值列,可以通过函数keyedStreamTable来创建。但与keyed table的设计目的不同,keyedstreamtable的目的是为了在高可用场景(多个发布端同时写入)下,避免重复消息。通常key就是消息的ID。

    • 数据操作特点

    由于流数据具有一旦生成就不会发生变化的特点,因此流数据表不支持更新和删除记录,只支持查询和添加记录。流数据通常具有连续性,而内存是有限的。为解决这个矛盾,流数据表引入了持久化机制,在内存中保留最新的一部分数据,更旧的数据持久化在磁盘上。当用户订阅旧的数据时,直接从磁盘上读取。启用持久化,使用函数enableTableShareAndPersistence,具体参考流数据教程

    • 应用场景

    共享的流数据表在流计算中发布数据。订阅端通过subscribeTable函数来订阅和消费流数据。

     

    1.4 MVCC内存表

    MVCC内存表存储了多个版本的数据,当多个用户同时对MVCC内存表进行读写操作时,互不阻塞。MVCC内存表的数据隔离采用了快照隔离模型,用户读取到的是在他读之前就已经存在的数据,即使这些数据在读取的过程中被修改或删除了,也对之前正在读的用户没有影响。这种多版本的方式能够支持用户对内存表的并发访问。需要说明的是,当前的MVCC内存表实现比较简单,更新和删除数据时锁定整个表,并使用copy-on-write技术复制一份数据,因此对数据删除和更新操作的效率不高。在后续的版本中,我们将实现行级的MVCC内存表。

    • 创建

    使用mvccTable函数创建MVCC内存表。例如:

    //创建空的流数据表
    t=mvccTable(1:0,`sym`id`val,[SYMBOL,INT,INT])
    
    //使用向量创建流数据表
    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    t=mvccTable(sym,id,val)

    我们可以将MVCC内存表的数据持久化到磁盘,只需创建时指定持久化的目录和表名即可。例如,

    t=mvccTable(1:0,`sym`id`val,[SYMBOL,INT,INT],"/home/user1/DolphinDB/mvcc","test")

    系统重启后,我们可以通过loadMvccTable函数将磁盘中的数据加载到内存中。

    loadMvccTable("/home/user1/DolphinDB/mvcc","test")

    我们也可以使用mvccTable函数将常规内存表转换为MVCC内存表。

    sym=`A`B`C`D`E
    id=5 4 3 2 1
    val=52 64 25 48 71
    tmp=table(sym, id, val)
    t=mvccTable(tmp)
    • 应用场景

    当前的MVCC内存表适用于读多写少,并有持久化需要的场景。譬如动态的配置系统,需要持久化配置项,配置项的改动不频繁,已新增和查询操作为主,非常适合MVCC表。

     

    2. 共享内存表

    DolphinDB中的内存表默认只在创建内存表的会话中使用,不支持多用户多会话的并发操作,当然对别的会话也不可见。如果希望创建的内存表能被别的用户使用,保证多用户并发操作的安全,必须共享内存表。4种类型的内存表均可共享。在DolphinDB中,我们使用share命令将内存表共享。

    t=table(1..10 as id,rand(100,10) as val)
    share t as st
    //或者share(t,`st)

    上面的代码将表t共享为表st。

    使用undef函数可以删除共享表。

    undef(`st,SHARED)

    2.1 保证对所有会话可见

    内存表仅在当前会话可见,在其他会话中不可见。共享之后,其他会话可以通过访问共享变量来访问内存表。例如,我们在当前会话中把表t共享为表st。

    t=table(1..10 as id,rand(100,10) as val)
    share t as st

    我们可以在其他会话中访问变量st。例如,往共享表st插入一条数据。

    insert into st values(11,200)
    select * from st
    
    id val
    -- ---
    1  1  
    2  53 
    3  13 
    4  40 
    5  61 
    6  92 
    7  36 
    8  33 
    9  46 
    10 26 
    11 200

    切换到原来的会话,我们可以发现,表t中也增加了一条记录。

    select * from t
    
    id val
    -- ---
    1  1  
    2  53 
    3  13 
    4  40 
    5  61 
    6  92 
    7  36 
    8  33 
    9  46 
    10 26 
    11 200

     

    2.2 保证线程安全

    在多线程的情况下,内存表中的数据很容易被破坏。共享则提供了一种保护机制,能够保证数据安全,但同时也会影响系统的性能。

    常规内存表、流数据表和MVCC内存表都支持多版本模型,允许多读一写。具体说,读写互不阻塞,写的时候可以读,读的时候可以写。读数据时不上锁,允许多个线程同时读取数据,读数据时采用快照隔离(snapshot isolation)。写数据时必须加锁,同时只允许一个线程修改内存表。写操作包括添加,删除或更新。添加记录一律在内存表的末尾追加,无论内存使用还是CPU使用均非常高效。常规内存表和MVCC内存表支持更新和删除,且采用了copy-on-write技术,也就是先复制一份数据(构成一个新的版本),然后在新版本上进行删除和修改。由此可见删除和更新操作无论内存和CPU消耗都比较高。当删除和更新操作很频繁,读操作又比较耗时(不能快速释放旧的版本),容易导致OOM异常。

    键值内存表写入时需维护内部索引,读取时也需要根据索引获取数据。因此键值内存表共享采用了不同的方法,无论读写都必须加锁。写线程和读线程,多个写线程之间,多个读线程之间都是互斥的。对键值内存表尽量避免耗时的查询或计算,否则会使其它线程长时间处于等待状态。

     

    3. 分区内存表

    当内存表数据量较大时,我们可以对内存表进行分区。分区后一个大表有多个子表(tablet)构成,大表不使用全局锁,锁由每个子表独立管理,这样可以大大增加读写并发能力。DolphinDB支持对内存表进行值分区、范围分区、哈希分区和列表分区,不支持组合分区。在DolphinDB中,我们使用函数createPartitionedTable创建内存分区表。

    • 创建分区常规内存表
    t=table(1:0,`id`val,[INT,INT]) 
    db=database("",RANGE,0 101 201 301) 
    pt=db.createPartitionedTable(t,`pt,`id)
    • 创建分区键值内存表
    kt=keyedTable(1:0,`id`val,[INT,INT]) 
    db=database("",RANGE,0 101 201 301) 
    pkt=db.createPartitionedTable(t,`pkt,`id)
    • 创建分区流数据表

    创建分区流数据表时,需要传入多个流数据表作为模板,每个流数据表对应一个分区。写入数据时,直接往这些流表中写入;而查询数据时,需要查询分区表。

    st1=streamTable(1:0,`id`val,[INT,INT]) 
    st2=streamTable(1:0,`id`val,[INT,INT]) 
    st3=streamTable(1:0,`id`val,[INT,INT]) 
    db=database("",RANGE,1 101 201 301) pst=db.createPartitionedTable([st1,st2,st3],`pst,`id)  
    st1.append!(table(1..100 as id,rand(100,100) as val)) 
    st2.append!(table(101..200 as id,rand(100,100) as val)) 
    st3.append!(table(201..300 as id,rand(100,100) as val))  
    select * from pst
    • 创建分区MVCC内存表

    与创建分区流数据表一样,创建分区MVCC内存表,需要传入多个MVCC内存表作为模板。每个表对应一个分区。写入数据时,直接往这些表中写入;而查询数据时,需要查询分区表。

    mt1=mvccTable(1:0,`id`val,[INT,INT])
    mt2=mvccTable(1:0,`id`val,[INT,INT])
    mt3=mvccTable(1:0,`id`val,[INT,INT])
    db=database("",RANGE,1 101 201 301)
    pmt=db.createPartitionedTable([mt1,mt2,mt3],`pst,`id)
    
    mt1.append!(table(1..100 as id,rand(100,100) as val))
    mt2.append!(table(101..200 as id,rand(100,100) as val))
    mt3.append!(table(201..300 as id,rand(100,100) as val))
    
    select * from pmt

    由于分区内存表不使用全局锁,创建以后不能再动态增删子表。


    3.1 增加查询的并发性

    分区表增加查询的并发性有三层含义:(1)键值表在查询时也需要加锁,分区表由子表独立管理锁,相当于把锁的粒度变细了,因此可以增加读的并发性;(2)批量计算时分区表可以并行处理每个子表;(3)如果SQL查询的过滤指定了分区字段,那么可以缩小分区范围,避免全表扫描。

    以键值内存表为例,我们对比在分区和不分区的情况下,并发查询的性能。首先,创建模拟数据集,一共包含500万行数据。

    n=5000000
    id=shuffle(1..n)
    qty=rand(1000,n)
    price=rand(1000.0,n)
    kt=keyedTable(`id,id,qty,price)
    share kt as skt
    
    id_range=cutPoints(1..n,20)
    db=database("",RANGE,id_range)
    pkt=db.createPartitionedTable(kt,`pkt,`id).append!(kt)
    share pkt as spkt

    我们在另外一台服务器上模拟10个客户端同时查询键值内存表。每个客户端查询10万次,每次查询一条数据,统计每个客户端查询10万次的总耗时。

    def queryKeyedTable(tableName,id){
    	for(i in id){
    		select * from objByName(tableName) where id=i
    	}
    }
    conn=xdb("192.168.1.135",18102,"admin","123456")
    n=5000000
    
    jobid1=array(STRING,0)
    for(i in 1..10){
    	rid=rand(1..n,100000)
    	s=conn(submitJob,"evalQueryUnPartitionTimer"+string(i),"",evalTimer,queryKeyedTable{`skt,rid})
    	jobid1.append!(s)
    }
    time1=array(DOUBLE,0)
    for(j in jobid1){
    	time1.append!(conn(getJobReturn,j,true))
    }
    
    jobid2=array(STRING,0)
    for(i in 1..10){
    	rid=rand(1..n,100000)
    	s=conn(submitJob,"evalQueryPartitionTimer"+string(i),"",evalTimer,queryKeyedTable{`spkt,rid})
    	jobid2.append!(s)
    }
    time2=array(DOUBLE,0)
    for(j in jobid2){
    	time2.append!(conn(getJobReturn,j,true))
    }

    time1是10个客户端查询未分区键值内存表的耗时,time2是10个客户端查询分区键值内存表的耗时,单位是毫秒。

    time1
    [6719.266848,7160.349678,7271.465094,7346.452625,7371.821485,7363.87979,7357.024299,7332.747157,7298.920972,7255.876976]
    
    time2
    [2382.154581,2456.586709,2560.380315,2577.602019,2599.724927,2611.944367,2590.131679,2587.706832,2564.305815,2498.027042]

    可以看到,每个客户端查询分区键值内存表的耗时要低于查询未分区内存表的耗时。

    查询未分区的内存表,可以保证快照隔离。但查询一个分区内存表,不再保证快照隔离。如前面所说分区内存表的读写不使用全局锁,一个线程在查询时,可能另一个线程正在写入而且涉及多个子表,从而可能读到一部分写入的数据。


    3.2 增加写入的并发性

    以分区的常规内存表为例,我们可以同时往不同的分区写入数据。

    t=table(1:0,`id`val,[INT,INT])
    db=database("",RANGE,1 101 201 301)
    pt=db.createPartitionedTable(t,`pt,`id)
    
    def writeData(mutable t,id,batchSize,n){
    	for(i in 1..n){
    		idv=take(id,batchSize)
    		valv=rand(100,batchSize)
    		tmp=table(idv,valv)
    		t.append!(tmp)
    	}
    }
    
    job1=submitJob("write1","",writeData,pt,1..100,1000,1000)
    job2=submitJob("write2","",writeData,pt,101..200,1000,1000)
    job3=submitJob("write3","",writeData,pt,201..300,1000,1000)

    上面的代码中,同时有3个线程对pt的3个不同的分区进行写入。需要注意的是,我们要避免同时对相同分区进行写入。例如,下面的代码可能会导致系统崩溃。

    job1=submitJob("write1","",writeData,pt,1..300,1000,1000)
    job2=submitJob("write2","",writeData,pt,1..300,1000,1000)

    上面的代码定义了两个写入线程,并且写入的分区相同,这样会破坏内存。为了保证每个分区数据的安全性和一致性,我们可将分区内存表共享。这样即可定义多个线程同时对相同分区分入。

    share pt as spt
    job1=submitJob("write1","",writeData,spt,1..300,1000,1000)
    job2=submitJob("write2","",writeData,spt,1..300,1000,1000)


    4. 数据操作比较


    4.1 增删改查

    下表总结了4种类型内存表在共享/分区的情况下支持的增删改查操作。

    说明:

    • 常规内存表、键值内存表、MVCC内存表都支持增删改查操作,流数据表仅支持增加数据和查询,不支持删除和更新操作。
    • 对于键值内存表,如果查询的过滤条件中包含主键,查询的性能会得到明显提升。
    • 对于分区内存表,如果查询的过滤条件中包含分区列,系统能够缩小要扫描的分区范围,从而提升查询的性能。


    4.2 并发性

    在没有写入的情况下,所有内存表都允许多个线程同时查询。在有写入的情况下,4种内存表的并发性有所差异。下表总结了4种内存表在共享/分区的情况下支持的并发读写情况。

    说明:

    • 共享表允许并发读写。
    • 对于没有共享的分区表,不允许多线程对相同分区同时写入的。


    4.3 持久化

    • 常规内存表和键值内存表不支持数据持久化。一旦节点重启,内存中的数据将全部丢失。
    • 只有空的流数据表才支持数据持久化。要对流数据表进行持久化,首先要配置流数据持久化的目录persistenceDir,再使用enableTableShareAndPersistence使用将流数据表共享,并持久化到磁盘上。例如,将流数据表t共享并持久化到磁盘上。
    t=streamTable(1:0,`id`val,[INT,INT])
    enableTableShareAndPersistence(t,`st)

    流数据表启用了持久化后,内存中仍然会保留流数据表中部分最新的记录。默认情况下,内存会保留最新的10万条记录。我们也可以根据需要调整这个值。

    流数据表持久化可以设定采用异步/同步、压缩/不压缩的方式。通常情况下,异步模式能够实现更高的吞吐量。

    系统重启后,再次执行enableTableShareAndPersistence函数,会将磁盘中的所有数据加载到内存。

    • MVCC内存表支持持久化。在创建MVCC内存表时,我们可以指定持久化的路径。例如,创建持久化的MVCC内存表。
    t=mvccTable(1:0,`id`val,[INT,INT],"/home/user/DolphinDB/mvccTable")
    t.append!(table(1..10 as id,rand(100,10) as val))

    系统重启后,我们可以使用loadMvccTable函数将磁盘中的数据加载到内存中。例如:

    t=loadMvccTable("/home/user/DolphinDB/mvccTable","t")

    5. 表结构操作比较

    内存表的结构操作包括新增列、删除列、修改列(内容和数据类型)以及调整列的顺序。下表总结了4种类型内存表在共享/分区的情况下支持的结构操作。

    说明:

    • 分区表以及MVCC内存表不能通过addColumn函数新增列。
    • 分区表可以通过update语句来新增列,但是流数据表不允许修改,因此流数据表不能通过update语句来新增列。


    6. 小结

    DolphinDB支持4种类型内存表,还引入了共享和分区的概念,基本能够满足内存计算和流计算的各种需求。

    展开全文
  • DolphinDB是一款支持多用户多任务并发操作的高性能分布式时序数据库软件(distributed time-series database)。针对大数据的高效的内存管理是其性能优异的原因之一。本教程涉及的内存管理包括以下方面: 变量的内存...

    DolphinDB是一款支持多用户多任务并发操作的高性能分布式时序数据库软件(distributed time-series database)。针对大数据的高效的内存管理是其性能优异的原因之一。本教程涉及的内存管理包括以下方面:

    • 变量的内存管理:为用户提供与回收编程环境所需内存。
    • 分布式表的缓存管理:多个session共享分区表数据,以提高内存使用率。
    • 流数据缓存:流数据发送节点提供持久化和发送队列缓存,订阅节点提供接收数据队列缓存。
    • DFS数据库写入缓存:写入DFS的数据先写到WAL和缓存,通过批量写入提升吞吐量。


    1. 内存管理机制

    DolphinDB向操作系统申请内存块,自行进行管理。当申请的内存块闲置时,系统会定期检查并释放。目前vector和table以及所有字符串的内存分配都已经纳入DolphinDB的内存管理系统。

    通过参数maxMemSize设定节点的最大内存使用量:该参数制定节点的最大可使用内存。如果设置太小,会严重限制集群的性能,如果设置太大,例如超过物理内存,可能会触发操作系统强制关闭进程。若机器内存为16GB,并且只部署1个节点,建议将该参数设置为12GB左右。

    以512MB为单位向操作系统申请内存块:当用户查询操作或者编程换进所需要内存时,DolphinDB会以512MB为单位向操作系统申请内存。如果操作系统无法提供大块的连续内存,则会尝试256MB,128MB等更小的内存块。

    系统充分利用可用内存缓存数据库数据:当节点的内存使用总量小于maxMemSize时,DolphinDB会尽可能多的缓存数据库分区数据,以便提升用户下次访问该数据块的速度。当内存不足时,系统自动会剔除部分缓存。

    每隔30秒扫描一次,空闲的内存块还给操作系统:当用户使用释放内存中变量,或者使用函数clearAllCache释放缓存时,如果内存块完全空闲,则会整体还给操作系统,如果仍有小部分内存在使用,比如512MB的内存块中仍有10MB在使用,则不会归还操作系统。


    2. 变量的内存管理

    2.1 创建变量

    在DolphinDB节点上,先创建一个用户user1,然后登陆。创建一个vector,含有1亿个INT类型元素,约400MB。

    示例1. 创建vector变量

     login("admin","123456")  //创建用户需要登陆admin
    createUser("user1","123456")
    login("user1","123456")
    v = 1..100000000
    sum(mem().blockSize - mem().freeSize) //输出内存占用结果

    结果为: 402,865,056,内存占用400MB左右,符合预期。

    再创建一个table,1000万行,5列,每列4字节,约200MB。

    示例2. 创建table变量

    n = 10000000
    t = table(n:n,["tag1","tag2","tag3","tag4","tag5"],[INT,INT,INT,INT,INT])
    (mem().blockSize - mem().freeSize).sum()

    结果为:612,530,448,约600MB,符合预期。


    2.2 释放变量

    可通过undef函数,释放变量的内存。

    示例3. 使用undef函数或者赋值为NULL释放变量

    undef(`v)

    或者

    v = NULL

    除了手动释放变量,当session关闭时,比如关闭GUI和其他API连接,都会触发对该session的所有内存进行回收。当通过web notebook连接时,10分钟内无操作,系统会关闭session,自动回收内存。


    3. 分布式表的缓存管理

    DolphinDB对分布式表是以分区为单位管理的。分布式表的缓存是全局共享的,不同的session或读事务在大部分情况下,会看到同一份数据copy(版本可能会有所不同),这样极大的节省了内存的使用。

    历史数据库都是以分布式表的形式存在数据库中,用户平时查询操作也往往直接与分布式表交互。分布式表的内存管理有如下特点:

    • 内存以分区列为单位进行管理。
    • 数据只加载到所在的节点,不会在节点间转移。
    • 多个用户访问相同分区时,使用同一份缓存。
    • 内存使用不超过maxMemSize情况下,尽量多缓存数据。
    • 缓存数据达到maxMemSize时,系统自动回收。

    以下多个示例是基于以下集群:部署于2个节点,采用单副本模式。按天分30个区,每个分区1000万行,11列(1列DATE类型,1列INT类型,9列LONG类型),所以每个分区的每列(LONG类型)数据量为1000万行 * 8字节/列 = 80M,每个分区共1000万行 * 80字节/行 = 800M,整个表共3亿行,大小为24GB。

    函数clearAllCache()可清空已经缓存的数据,下面的每次测试前,先用该函数清空节点上的所有缓存。


    3.1 内存以分区列为单位进行管理

    DolphinDB采用列式存储,当用户对分布式表的数据进行查询时,加载数据的原则是,只把用户所要求的分区和列加载到内存中。

    示例4. 计算分区2019.01.01最大的tag1的值。该分区储存在node1上,可以在controller上通过函数getClusterChunksStatus()查看分区分布情况,而且由上面可知,每列约80MB。在node1上执行如下代码,并查看内存占用。

    select max(tag1) from loadTable(dbName,tableName) where day = 2019.01.01
    sum(mem().blockSize - mem().freeSize) 

    输出结果为84,267,136。我们只查询1个分区的一列数据,所以把该列数据全部加载到内存,其他的列不加载。

    示例5. 在node1 上查询 2019.01.01的前100条数据,并观察内存占用。

    select top 100 * from loadTable(dbName,tableName) where day = 2019.01.01
    sum(mem().blockSize - mem().freeSize)

    输出结果为839,255,392。虽然我们只取100条数据,但是DolphinDB加载数据的最小单位是分区列,所以需要加载每个列的全部数据,也就是整个分区的全部数据,约800MB。

    注意: 合理分区以避免"out of memory":DolphinDB是以分区为单位管理内存,因此内存的使用量跟分区关系密切。假如用户分区不均匀,导致某个分区数据量超大,甚至机器的全部内存都不足以容纳整个分区,那么当涉及到该分区的查询计算时,系统会抛出"out of memory"的异常。一般原则,如果用户设置maxMemSize=8,则每个分区常用的查询列之和为100-200MB为宜。如果表有10列常用查询字段,每列8字段,则每个分区约100-200万行。


    3.2 数据只加载到所在的节点

    在数据量大的情况下,节点间转移数据是非常耗时的操作。DolphinDB的数据是分布式存储的,当执行计算任务时,把任务发送到数据所在的节点,而不是把数据转移到计算所在的节点,这样大大降低数据在节点间的转移,提升计算效率。

    示例6. 在node1上计算两个分区中tag1的最大值。其中分区2019.01.02数组存储在node1上,分区2019.01.03数据存储在node2上。

    select max(tag1) from loadTable(dbName,tableName) where day in [2019.01.02,2019.01.03]
    sum(mem().blockSize - mem().freeSize) 

    输出结果为84,284,096。在node2上用查看内存占用结果为84,250,624。每个节点存储的数据都为80M左右,也就是node1上存储了分区2019.01.02的数据,node2上存储了2019.01.03的数据。

    示例7. 在node1上查询分区2019.01.02和2019.01.03的所有数据,我们预期node1加载2019.01.02数据,node2加载2019.01.03的数据,都是800M左右,执行如下代码并观察内存。

    select top 100 * from loadTable(dbName,tableName) where day in [2019.01.02,2019.01.03]
    sum(mem().blockSize - mem().freeSize)

    node1上输出结果为839,279,968。node2上输出结果为839,246,496。结果符合预期。

    注意: 谨慎使用没有过滤条件的"select *",因为这会将所有数据载入内存。在列数很多的时候尤其要注意该点,建议仅加载需要的列。若使用没有过滤条件的"select top 10 *",会将第一个分区的所有数据载入内存。


    3.3 多个用户访问相同分区时,使用同一份缓存

    DolphinDB支持海量数据的并发查询。为了高效利用内存,对相同分区的数据,内存中只保留同一份副本。

    示例8. 打开两个GUI,分别连接node1和node2,查询分区2019.01.01的数据,该分区的数据存储在node1上。

    select * from loadTable(dbName,tableName) where date = 2019.01.01
    sum(mem().blockSize - mem().freeSize)

    上面的代码不管执行几次,node1上内存显示一直是839,101,024,而node2上无内存占用。因为分区数据只存储在node1上,所以node1会加载所有数据,而node2不占用任何内存。


    3.4 节点内存占用情况与缓存数据的关系

    3.4.1 节点内存使用不超过maxMemSize情况下,尽量多缓存数据

    通常情况下,最近访问的数据往往更容易再次被访问,因此DolphinDB在内存允许的情况下(内存占用不超过用户设置的maxMemSize),尽量多缓存数据,来提升后续数据的访问效率。

    示例9. 数据节点设置的maxMemSize=8。连续加载9个分区,每个分区约800M,总内存占用约7.2GB,观察内存的变化趋势。

    days = chunksOfEightDays();
    for(d in days){
        select * from loadTable(dbName,tableName) where  = day
        sum(mem().blockSize - mem().freeSize)
    }

    内存随着加载分区数的增加变化规律如下图所示:

    当遍历每个分区数据时,在内存使用量不超过maxMemSize的情况下,分区数据会全部缓存到内存中,以在用户下次访问时,直接从内存中提供数据,而不需要再次从磁盘加载。

     

    3.4.2 节点内存使用达到maxMemSize时,系统自动回收


    如果DolphinDB server使用的内存,没有超过用户设置的maxMemSize,则不会回收内存。当总的内存使用达到maxMemSize时,DolphinDB 会采用LRU的内存回收策略, 来腾出足够的内存给用户。

    示例10. 上面用例只加载了8天的数据,此时我们继续共遍历15天数据,查看缓存达到maxMemSize时,内存的占用情况。如下图所示:

    如上图所示,当缓存的数据超过maxMemSize时,系统自动回收内存,总的内存使用量仍然小于用户设置的最大内存量8GB。

    示例11. 当缓存数据接近用户设置的maxMemSize时,继续申请Session变量的内存空间,查看系统内存占用。此时先查看系统的内存使用:

    sum(mem().blockSize - mem().freeSize)

    输出结果为7,550,138,448。内存占用超过7GB,而用户设置的最大内存使用量为8GB,此时我们继续申请4GB空间。

    v = 1..1000000000
    sum(mem().blockSize - mem().freeSize)

    输出结果为8,196,073,856。约为8GB,也就是如果用户定义变量,也会触发缓存数据的内存回收,以保证有足够的内存提供给用户使用。


    4. 流数据消息缓存队列

    当数据进入流数据系统时,首先写入流表,然后写入持久化队列和发送队列(假设用户设置为异步持久化),持久化队列异步写入磁盘,将发送队列发送到订阅端。

    当订阅端收到数据后,先放入接受队列,然后用户定义的handler从接收队列中取数据并处理。如果handler处理缓慢,会导致接收队列有数据堆积,占用内存。如下图所示:

    流数据内存相关的配置选项:

    • maxPersistenceQueueDepth: 流表持久化队列的最大消息数。对于异步持久化的发布流表,先将数据放到持久化队列中,再异步持久化到磁盘上。该选项默认设置为1000万。在磁盘写入成为瓶颈时,队列会堆积数据。
    • maxPubQueueDepthPerSite: 最大消息发布队列深度。针对某个订阅节点,发布节点建立一个消息发布队列,该队列中的消息发送到订阅端。默认值为1000万,当网络出现拥塞时,该发送队列会堆积数据。
    • maxSubQueueDepth: 订阅节点上最大的每个订阅线程最大的可接收消息的队列深度。订阅的消息,会先放入订阅消息队列。默认设置为1000万,当handler处理速度较慢,不能及时处理订阅到的消息时,该队列会有数据堆积。
    • 流表的capacity:在函数enableTablePersistence()中第四个参数指定,该值表示流表中保存在内存中的最大行数,达到该值时,从内存中删除一半数据。当流数据节点中,流表比较多时,要整体合理设置该值,防止内存不足。

    运行过程,可以通过函数getStreamingStat()来查看流表的大小以及各个队列的深度。


    5. 为写入DFS数据库提供缓存

    DolphinDB为了提高读写的吞吐量和降低读写的延迟,采用先写入WAL和缓存的通用做法,等累积到一定数量时,批量写入。这样减少和磁盘文件的交互次数,提升写入性能,可提升写入速度30%以上。因此,也需要一定的内存空间来临时缓存这些数据,如下图所示:

    当事务t1,t2,t3都完成时,将三个事务的数据一次性写入到DFS的数据库磁盘上。Cache Engine空间一般推荐为maxMemSize的1/8~1/4,可根据最大内存和写入数据量适当调整。CacheEngine的大小可以通过配置参数chunkCacheEngineMemSize来配置。

    • chunkCacheEngineMemSize:指定cache engine的容量。cache engine开启后,写入数据时,系统会先把数据写入缓存,当缓存中的数据量达到chunkCacheEngineMemSize的30%时,才会写入磁盘。


    6. 高效使用内存

    在企业的生产环境中,DolphinDB往往作为流数据中心以及历史数据仓库,为业务人员提供数据查询和计算。当用户较多时,不当的使用容易造成Server端内存耗尽,抛出"out of memory" 异常。可遵循以下建议,尽量避免内存的不合理使用。

    • 合理均匀分区:DolphinDB是以分区为单位加载数据,因此,分区大小对内存影响巨大。合理均匀的分区,不管对内存使用还是对性能而言,都有积极的作用。因此,在创建数据库的时候,根据数据规模,合理规划分区大小。每个分区的常用字段数据量约100MB左右为宜。
    • 及时释放数据量较大的变量:若用户创建数据量较大的变量,例如v = 1..10000000,或者将含有大量数据的查询结果赋值给一个变量t = select * from t where date = 2010.01.01,v和t将会在用户的session占用大量的内存。如果不及时释放,当其他用户申请内存时,就有可能因为内存不足而抛出异常。
    • 只查询需要的列:避免使用select *,如果用select *会把该分区所有列加载到内存。实际中,往往只需要几列。因此为避免内存浪费,尽量明确写出所有查询的列,而不是用*代替。
    • 数据查询尽可能使用分区过滤条件:DolphinDB按照分区进行数据检索,如果不加分区过滤条件,则会全部扫描所有数据,数据量大时,内存很快被耗尽。有多个过滤条件的话,要优先写分区的过滤条件。
    • 尽快释放不再需要的变量或者session:根据以上分析可知,用户的私有变量在创建的session里面保存。session关闭的时候,会回收这些内存。因此,尽早使用undef函数或者关闭session来释放内存。
    • 合理配置流数据的缓存区:一般情况下流数据的容量(capacity)会直接影响发布节点的内存占用。比如,capacity设置1000万条,那么流数据表在超过1000万条时,会回收约一半的内存占用,也就是内存中会保留500万条左右。因此,应根据发布节点的最大内存,合理设计流表的capacity。尤其是在多张发布表的情况,更需要谨慎设计。


    7. 内存监控及常见问题


    7.1 内存监控


    7.1.1 controller上监控集群中节点内存占用

    在controller上提供函数getClusterPerf()函数,显示集群中各个节点的内存占用情况。包括:

    MemAlloc:节点上分配的总内存,近似于向操作系统申请的内存总和。

    MemUsed:节点已经使用的内存。该内存包括变量、分布式表缓存以及各种缓存队列等。

    MemLimit:节点可使用的最大内存限制,即用户配置的maxMemSize。

     

    7.1.2 mem()函数监控某个节点内存占用

    mem()函数可以显示整个节点的内存分配和占用情况。该函数输出4列,其中列blockSize表示分配的内存块大小,freeSize表示剩余的内存块大小,通过sum(mem().blockSize - mem().freeSize) 得到节点所使用的总的内存大小。


    7.1.3 监控节点上不同session的内存占用

    可通过函数getSessionMemoryStat()查看节点上每个session占用的内存量,该内存只包含session内定义的变量。当节点上内存占用太高时,可以通过该函数排查哪个用户使用了大量的内存。


    7.1.4 查看某个对象占用的内存大小

    通过函数memSize来查看某个对象占用内存的具体大小,单位为字节。比如:

    v=1..1000000
    memSize(v)

    输出:4000000。


    7.2 常见问题


    7.2.1 监控显示节点内存占用太高

    通过上面的分析可知,DolphinDB会在内存允许的情况下,会尽可能多的缓存数据。因此,如果只显示节点内存占用太高,接近maxMemSize,而没有其他内存相关的错误,那么这种情况是正常的。 如果出现"out of memory"等类似的错误,首先可以通过函数getSessionMemoryStat()查看各个session占用的内存大小,其次通过函数clearAllCache()来手动释放节点的缓存数据。

    7.2.2 MemAlloc显示值跟操作系统实际显示值有差异

    DolphinDB是C++程序,本身需要一些基础的数据结构和内存开销,MemAlloc显示内存不包括这些内存,如果两者显示相差不大,几百MB以内,都属于正常现象。


    7.2.3 查询时,报告"out of memory"

    该异常往往是由于query所需的内存大于系统可提供的内存导致的。可能由以下原因导致:

    • 查询没有加分区过滤条件或者条件太宽,导致单个query涉及的数据量太大。
    • 分区不均匀。可能某个分区过大,该分区的数据超过节点配置的最大内存。
    • 某个session持有大的变量,导致节点可用的内存很小。

    7.2.4 查询时,DolphinDB进程退出,没有coredump产生

    这种情况往往是由于给节点分配的内存超过系统物理内存的限制,操作系统把DolphinDB强制退出。Linux上可以通过操作系统的日志查看原因。


    7.2.5 执行clearAllCache()函数后,MemUsed没有明显降低

    可以通过getSessionMemoryStst()查看各个session占用的内存大小。可能是由于某个session持有占用大量内存的变量不释放,导致该部分内存一直不能回收。

    展开全文
  • 三星内存铭牌详解|三星内存条标签内存参数详解 大多数朋友都清楚内存铭牌上,记录着内存的重要数据。但是大多数朋友都对此不甚了然!为此小编也想学习下,现在把相关的学习笔记分享出来,希望和朋友们显摆下,小编...
  • 一、内存频率的影响因素 1.内存条标注的频率 这个频率,是在外界因素(cpu、主板)不构成影响时,该内存条保底能跑多少频率 什么意思呢?可以好比与货车载货:假设某货车载重50T,那么它保底能载50T的货物,它当然能...
  • 宏旺半导体ICMAX此次为大家带来的是关于内存时序那些事,平常我们在购买内存时,每一款内存的外包装盒上都会标明,那么这四组数字(如下图)到底是什么意思呢?这四组数字就是内存时序,这个数值也是决定内存性能的...
  • 内存时序图分析

    2019-11-13 21:11:35
    内存相关缩写的含义 ... 内存读取时序图中的Toh --> 当Address,CE#和OE#中的一个或多个拉高后,数据的保持时间。大白话就是当发出停止信号时数据只会保持Toh,这里Toh是0ns,所以就是当发...
  • IIC总线时序详解

    万次阅读 2017-07-06 09:52:45
    I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C总线产生于在80年代,最初为...可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全
  • 时序数据往往是由百万级甚至千万级终端设备产生的,写入并发量比较高,属于海量数据场景。
  • DDR2_SDRAM操作时序(中文版),解决英文阅读不熟练同事们的困扰
  • spi协议时序图和四种模式实际应用详解

    千次阅读 多人点赞 2022-02-25 13:51:26
    上个章节我们讲解了spi接口定义,今天我们更加深入讲解下spi协议时序图和spi四种模式的用法。 刚开始接触单片机开发时,最怕就是看时序图,对于我来说就是奇怪的知识。 特别是SPI和IIC的,以前写程序都直接复制...
  • DDR3内存详解,存储器结构+时序+初始化过程 2017-06-17 16:10:33a_chinese_man阅读数 23423更多 分类专栏:硬件开发基础 转自:http://www.360doc.com/content/14/0116/16/15528092_345730642.shtml 首先,...
  • DDR时序参数详解(转载)

    万次阅读 2019-06-14 15:49:00
    转自: ...2、Post CAS技术在单次的突发访问中是没有影响的,只有连续多次的突发访问才有性能的提升,但是对于内存操作一般不可能做单次的突发,就算程序这样做了硬件缓存机制也会做多次的突发。
  • Java内存模型详解

    2019-09-01 09:58:07
    Java内存模型(Java Memory Model,简称JMM),即Java虚拟机定义的一种用来屏蔽各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能够达到一致的内存访问效果的内存模型。本篇文章大致设涉及到五个...
  • 将上面的例子稍加改造来展示这种内存序,假设flag为一个 atomic特化的bool 原子量,a为一个int变量,b、c各为一个bool变量,并且有如下时序的操作: step thread A thread B 1 b = true 2 a = 1 3 flag.store(b, ...
  • 每毫秒记录一下电脑内存的使用情况,然后就可以根据统计的数据,利用图形化界面(InfluxDB V1一般配合Grafana)制作内存使用情况的折线图;可以理解为按时间记录一些数据(常用的监控数据、埋点统计数据等)...
  • DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合...校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。 单线制串行接口, 使系统集成变得简易快捷。超小
  • JVM内存模型详解

    万次阅读 多人点赞 2018-02-09 14:24:27
    笔记大纲1、jvm内存结构图2、jvm按照线程共享和私有内存区域划分结构图3、堆和栈在功能、内存大小、线程共享私有进行比较4、JVM运行结构图5、线程安全本质时序图6、jdk6、7、8三个版本内存模型比较7、jdk1.8为什么将...
  • ML之时序详解

    2020-01-29 21:56:26
    动态图概念 : 从静态图中抽取瞬间值的变化描述系统随时间变化的行为, 动态图包括交互图活动图状态图, 这篇博客研究交互图 包括时序图和协作图; – 时序图 : 显示对象之间的关系, 强调对象之间消息的时间顺序, 显示...
  • Java 内存模型详解

    2021-09-02 23:00:05
    在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写 - 读内存中的公共状态来隐式进行通信。在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信。 同步...
  • UML之时序详解

    万次阅读 多人点赞 2015-12-21 19:10:42
    作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/17927131动态图概念 : 从静态图...– 时序图 : 显示对象之间的关系, 强调对象之间消息的时间顺序, 显示对象之间的交互; – 协作
  • 芯片组上电时序VIA 8237R上电原理 C0~C3的CPU的几个状态 C0:正常操作状态 C1:CPU 暂停(被软件控制) C2:STOP CLK 状态,STPCLK#发出,CPU进入停止状态,退出该状态的方法是CPUSTP3变为有效。 C3: 系统挂起 8237的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,219
精华内容 2,087
关键字:

内存时序详解