图数据库 NebulaGraph 的内存管理实践之 Memory Tracker

数据库的内存管理是数据库内核设计中的重要模块,内存的可度量、可管控是数据库稳定性的重要保障。同样的,内存管理对图数据库 NebulaGraph 也至关重要。

图数据库的多度关联查询特性,往往使图数据库执行层对内存的需求量巨大。本文主要介绍 NebulaGraph v3.4 版本中引入的新特性 Memory Tracker,希望通过 Memory Tracker 模块的引入,实现细粒度的内存使用量管控,降低 graphd 和 storaged 发生被系统 OOM kill 的风险,提升 NebulaGraph 图数据库的内核稳定性。

注:为了同代码保持对应,本文部分用词直接使用了英文,e.g. reserve 内存 quota。

可用内存

在进行 Memory Tracker 的介绍之前,这里先介绍下相关的背景知识:可用内存。

进程可用内存

在这里,我们简单介绍下各个模式下,系统是如何判断可用内存的。

物理机模式

数据库内核会读取系统目录 /proc/meminfo,来确定当前环境的实际内存和剩余内存,Memory Tracker 将“实际物理内存”作为“进程可以使用的最大内存”;

容器/cgroup 模式

nebula-graphd.conf 文件中有一个配置项 FLAG_containerized 用来判断是否数据库跑在容器上。将 FLAG_containerized(默认为 false)设置为 true 之后,内核会读取相关 cgroup path 下的文件,确定当前进程可以使用多少内存;cgroup 有 v1、v2 两个版本,这里以 v2 为例;

FLAG 默认值 解释
FLAG_cgroup_v2_memory_max_path /sys/fs/cgroup/memory.max 通过读取路径确定最大内存使用量
FLAG_cgroup_v2_memory_current_path /sys/fs/cgroup/memory.current 通过读取路径确定当前内存使用量

举个例子,在单台机器上分别控制 graphd 和 storaged 的内存额度。你可以通过以下步骤:

step1:设置 FLAG_containerized=true

step2:创建 /sys/fs/cgroup/graphd//sys/fs/cgroup/storaged/,并配置各自目录下的 memory.max

step3:在 etc/nebula-graphd.confetc/nebula-storaged.conf 添加相关配置

--containerized=true
--cgroup_v2_controllers=/sys/fs/cgroup/graphd/cgroup.controllers
--cgroup_v2_memory_stat_path=/sys/fs/cgroup/graphd/memory.stat
--cgroup_v2_memory_max_path=/sys/fs/cgroup/graphd/memory.max
--cgroup_v2_memory_current_path=/sys/fs/cgroup/graphd/memory.current

Memory Tracker 可用内存

在获取“进程可用内存”以后,系统需要将其换算成 Memory Tracker 可 track 的内存,“进程可用内存”与“Memory Tracker 可用内存”有一个换算公式;

memtracker_limit = ( total - FLAGS_memory_tracker_untracked_reserved_memory_mb ) * FLAGS_memory_tracker_limit_ratio

usable_memory

FLAG 默认值 解释 支持动态改
memory_tracker_untracked_reserved_memory_mb 50 M Memory Tracker 会管理通过 new/delete 申请的内存,但进程除了通过此种方式申请内存外,还可能存在其他方式占用的内存;比如通过调用底层的 malloc/free 申请,这些内存通过此 flag 控制,在计算时会扣除此部分未被 track 的内存。 Yes
memory_tracker_limit_ratio 0.8 指定 Memory Tracker 可以使用的内存比例,在一些场景,我们可能需要调小来防止 OOM。 Yes

这里来详细展开说下 memory_tracker_limit_ratio 的使用:

  • 在混合部署环境中,存在多个 graphd 或 storaged 混合部署是需要调小。比如 graphd 只占用 50% 内存,则需在 nebula-graphd.conf 中将其手动改成 0.5;
  • 取值范围:memory_tracker_limit_ratio 除了 (0,1] 取值范围外,还额外定义了两个特殊值:
    • 2:通过数据库内核感知当前系统运行环境的可用内存,动态调整可用内存。由于此种方式非实时,有一定的概率会感知不精准;
    • 3:limit 将被设成一个极大值,起到关闭 Memory Tracker 的效果;

Memory Tracker 的设计与实现方案

下面,讲下 Memory Tracker 的设计与实现。整体的 Memory Tracker 设计,包含 Global new/delete operatorMemoryStatssystem mallocLimiter 等几个子模块。这个部分着重介绍下 Global new/delete operator 和 MemoryStats 模块。

memory_tracker

Global new/delete operator

Memory Tracker 通过 overload 全局 new/delete operator,接管内存的申请和释放,从而做到在进行真正的内存分配之前,进行内存额度分配的管理。这个过程分解为两个步骤:

  • 第一步:通过 MemoryStats 进行内存申请的汇报;
  • 第二步:调用 jemalloc 发生真正的内存分配行为;

jemalloc:Memory Tracker 不改变底层的 malloc 机制,仍然使用 jemalloc 进行内存的申请和释放;

MemoryStats

全局的内存使用情况统计,通过 GlobalMemoryStats 和 ThreadMemoryStats 分别对全局内存和线程内部内存进行管理;

ThreadMemoryStats

thread_local 变量,执行引擎线程在各自的 ThreadMemoryStats 中维护线程的 MemoryStats,包括“内存 Reservation 信息”和“是否允许抛异常的 throwOnMemoryExceeded”;

  • Reservation

每个线程 reserve 了 1 MB 的内存 quota,从而避免频繁地向 GlobalMemoryStats 索要额度。不管是申请还是返还时,ThreadMemoryStats 都会以一个较大的内存块作为与全局交换的单位。

alloc:在本地 reserved 1 MB 内存用完了,才问全局要下一个 1 MB。通过此种方式来尽可能降低向全局 quota 申请内存的频率;

dealloc:返还的内存先加到线程的 reserved 中,当 reserve quota 超过 1 MB 时,还掉 1 MB,剩下的自己留着;

 // Memory stats for each thread.
 struct ThreadMemoryStats {
   ThreadMemoryStats();
   ~ThreadMemoryStats();
 
   // reserved bytes size in current thread
   int64_t reserved;
   bool throwOnMemoryExceeded{false};
 };
  • throwOnMemoryExceeded

线程在遇到超过内存额度时,是否 throw 异常。只有在设置 throwOnMemoryExceeded 为 true 时,才会 throw std::bad_alloc。需要关闭 throw std::bad_alloc 场景见 Catch std::bac_alloc 章节。

GlobalMemoryStats

全局内存额度,维护了 limit 和 used 变量。

  • limit:通过运行环境和配置信息,换算得到 Memory Tracker 可管理的最大内存。limit 同 Limiter 模块的作用,详细内存换算见上文“Memory Tracker 可用内存”章节;

  • used:原子变量,汇总所有线程汇报上来的已使用内存(包括线程 reserved 的部分)。如果 used + try_to_alloc > limit,且在 throwOnMemoryExceeded 为 true 时,则会抛异常std::bac_alloc

Catch std::bac_alloc

由于 Memory Tracker overload new/delete 会影响所有线程,包括三方线程。此时,throw bad_alloc 在一些第三方线程可能出现非预期行为。为了杜绝此类问题发生,我们采用在代码路径上主动开启内存检测,选择在算子、RPC 等模块主动开启内存检测;

算子的内存检测

在 graph/storage 的各个算子中,添加 try...catch (在当前线程进行计算/分配内存) 和 thenError (通过 folly::Executor 异步提交的计算任务),感知 Memory Tracker 抛出 std::bac_alloc。数据库再通过 Status 返回错误码,使查询失败;

在进行一些内存调试时,可通过打开 nebula-graphd.conf 文件中的 FLAGS_memory_tracker_detail_log 配置项,并调小 memory_tracker_detail_log_interval_ms 观察查询前后的内存使用情况;

folly::future 异步执行

thenValue([this](StorageRpcResponse<GetNeighborsResponse>&& resp) {
    memory::MemoryCheckGuard guard;
    // memory tracker turned on code scope
    return handleResponse(resp);
})
.thenError(folly::tag_t<std::bad_alloc>{},
    [](const std::bad_alloc&) {
    // handle memory exceed
})

同步执行

memory::MemoryCheckGuard guard; \
try {
    // ...
} catch (std::bad_alloc & e) { \
    // handle memory exceed
}

RPC 的内存检测

RPC 主要解决 Request/Response 对象的序列化/反序列化的内存额度控制问题,由于 storaged reponse 返回的数据均封装在 DataSet 数据结构中,所以问题转化为:DataSet 的序列化、反序列化过程中的内存检测。

序列化:DataSet 的对象构造在 NebulaGraph 算子返回结果逻辑中,默认情况下,已经开启内存检测;

反序列化:通过 MemoryCheckGuard 显式开启,在 StorageClientBase::getResponse's onError 可捕获异常;

错误码

为了便于分辨哪个模块发生问题,NebulaGraph 中还添加了相关错误码,分别表示 graphd 和 storaged 发生 memory exceeded 异常:

E_GRAPH_MEMORY_EXCEEDED = -2600, // Graph memory exceeded
E_STORAGE_MEMORY_EXCEEDED = -3600, // Storage memory exceeded

延伸阅读

  • 什么是 malloc 以及动态内存分配:http://en.wikipedia.org/wiki/C_dynamic_memory_allocation
  • jemalloc
    • 原始论文:http://www.bsdcan.org/2006/papers/jemalloc.pdf
    • Facebook 对 jemalloc 的优化:http://engineering.fb.com/2011/01/03/core-data/scalable-memory-allocation-using-jemalloc/

谢谢你读完本文 (///▽///)

Nebula Graph:一个开源的分布式图数据库
本文转载于网络 如有侵权请联系删除

相关文章

  • HarmonyOS实战之入门 HelloWorld

    欢迎大家关注我的CSDN博客:https://xdr630.blog.csdn.net/HarmonyOS文章专栏:https://blog.csdn.net/qq_41684621/category_10128500.html第一个入门应用:HelloWorld新建完项目之后,自带HelloWorld,在第一个案例中,我们主要学习以下几点:1.如何运行项目登录账号,Tools-->DeviceManager或点击右上角的头像 在这里插入图片描述 在这里插入图片描述选择并开启模拟器,这个模拟器是不需要下载的,运行在华为的服务器上,不占用本地资源每次运行时不超过一个小时,超过了重新开启就行了 在这里插入图片描述运行项目 在这里插入图片描述 在这里插入图片描述2.页面中的包含关系在鸿蒙当中,一个页面就是一个Ability 在这里插入图片描述为什么要有子页面的存在呢?直接在最外面的页面里面添加文本信息不更简单吗?一个鸿蒙APP安装包结构如下,一个Ability对应一个Hap包把三个hap包打包成一个APP 在这里插入图片描述鸿蒙有个特点:可分、可合如果要使用这个APP,不需要完整的把这

  • go语言微信公众号开发后台接口封装

    个人整理的小功能,把微信公众号开发涉及的一些常用接口做了个封装。业余时间做了个有意思的小功能,每天早上7点准时给发天气预报,每晚8点发布一条英语说说,提醒自己不能忘记学习。封装实现的功能有:开发者首次接入、创建菜单、删除菜单、发送模板消息、接收公众号前端推送、获取Token,获取关注者信息,获取用户个人信息,根据code获取个人信息(微信前端第三方应用页面接入授权会涉及。)这里再介绍下微信前端第三方应用如何获取微信个人openid和个人信息的功能实现思路。如何在微信前端开发的应用界面,获取用户openid和个人信息呢?方法还是有的,思路靠谱。就是文档里描述的那几步授权操作,先获取code,再跳转,后台获取在传给前端。附代码封装://WxReceiveCommonMsg接收普通消息 typeWxReceiveCommonMsgstruct{ ToUserNamestring//接收者开发者微信号 FromUserNamestring//发送者发送方帐号(一个OpenID) Contentstring//文本内容 CreateTimeint64//创建时间 MsgTypestri

  • JVM系列之:String.intern和stringTable

    简介StringTable是什么?它和String.intern有什么关系呢?在字符串对象的创建过程中,StringTable有起到了什么作用呢?一切的答案都在本文中,快来看看吧。intern简介intern是String类中的一个native方法,所以它底层是用c++来实现的。感兴趣的同学可以去查看下JVM的源码了解更多的内容。这里我们主要谈一下intern的作用。intern返回的是这个String所代表的对象,怎么理解呢?Stringclass维护了一个私有的Stringpool,这个Stringpool也叫StringTable,中文名字叫做字符串常量池。当我们调用intern方法的时候,如果这个StringTable中已经包含了一个相同的String对象(根据equals(Object)方法来判断两个String对象是否相等),那么将会直接返回保存在这个StringTable中的String。如果StringTable中没有相同的对象,那么这个String对象将会被加入StringTable,并返回这个String对象的引用。所以,当且仅当s.equals(t)的时候s.in

  • 边缘计算

    云计算这个词,想必大部分人都听说过,也大致明白它的作用。简单来说,云计算是计算服务的集中化,以最简单的形式利用共享数据中心基础设施和规模经济来降低成本。除了云计算之外,边缘计算这个词,现在也越来越多地出现在我们身边。那么,究竟什么是边缘计算呢?边缘计算,是一种分散式运算的架构。在这种架构下,将应用程序、数据资料与服务的运算,由网络中心节点,移往网络逻辑上的边缘节点来处理。或者说,边缘运算将原本完全由中心节点处理大型服务加以分解,切割成更小与更容易管理的部分,分散到边缘节点去处理。边缘节点更接近于用户终端装置,可以加快资料的处理与传送速度,减少延迟。边缘计算涵盖非常广泛的技术,包括点对点、网格计算、雾计算、区块链和内容传输网络(CDN),边缘计算在移动领域深受欢迎,现在几乎遍及各行各业。边缘计算和云计算的关系在很多情况下,边缘计算和云计算是共生关系。随着物联网、虚拟现实、增强现实等技术的发展与应用,未来将会出现数据大爆炸的状况。完全依赖云计算来进行数据传输和处理,将会造成巨大的网络延迟。边缘计算将数据在边缘节点进行处理能够有效减少数据的传输和处理,但通过云计算的远程存储仍然至关重要。云计

  • LeetCode-60-Permutation-Sequence

    LeetCode-60-Permutation-SequenceTheset[1,2,3,…,n]containsatotalofn!uniquepermutations. Bylistingandlabelingallofthepermutationsinorder,Wegetthefollowingsequence(ie,forn=3): "123" "132" "213" "231" "312" "321" Givennandk,returnthekthpermutationsequence.复制同样是排列组合的问题,这次不需要打印所有的排列了,只需要按照排列的顺序打印出第k个,很显然,思路不会是列出所有的排列,然后找第k个打印出来是吧。观察来看,以1,2,3,4为例,有4*3*2*1=24种排列,其中根据排列的顺序,按照第一个数字可以分为以下4种: 1*** 2*** 3124 3142 3214 3241 3412 3421 4*** ####方法一 复制第

  • CCF-腾讯犀牛鸟基金项目课题介绍(一)——机器学习&计算机视觉及模式识别

    CCF-腾讯犀牛鸟基金由腾讯与中国计算机学会联合发起,旨在通过搭建产学合作平台,连接产业实践问题与学术科研问题,支持海内外优秀青年学者开展与产业结合的前沿科研工作。2018年CCF-腾讯犀牛鸟基金共涵盖机器学习、计算机视觉及模式识别、语音技术、自然语言处理、大数据技术、区块链等6个重点技术领域,涉及31项研究命题。未来,我们将分三期对研究命题进行详细介绍,欢迎青年学者关注了解,希望大家可以从中找到适合自己的申报命题。一、机器学习1.1面向图数据的深度卷积网络研究深度神经网络在基于网格数据(如图片、语音以及文本等)的表示与识别上取得了令人瞩目的进展。然而,实际的机器学习任务往往需要处理一类重要的非网格数据——图,例如社交网络、学术引用网络、三维点云、分子模型等。针对图数据的卷积网络需要解决以下难点:1、图节点无位置和方向属性;2、不能明显获得节点的局部感受;3、对大图切割成小图是NP-Hard,难以实现mini-batch训练。建议研究方向:1)  利用卷积网络实现图节点的高效分类。2)  研究图上的快速池化操作,实现子图分类。3)  构建基于图数据的深度学习的分布式算法,实现超大规模深

  • 【分类战车SVM】第二话:线性分类

    分类战车SVM(第二话:线性分类)回复“SVM”查看本《分类战车SVM》系列的内容:第一话:开题话第二话:线性分类第三话:最大间隔分类器第四话:拉格朗日对偶问题(原来这么简单!)第五话:核函数(哦,这太神奇了!)第六话:SMO算法(像Smoke一样简单!)附录:用Python做SVM模型1.回顾上一集我们大致介绍了机器学习世界的一种新武器——支持向量机,代号为SVM(微信公众号“数说工作室”中回复“SVM1”查看)。它具有以下优良特性:小样本——SVM配备“支持向量”识别系统,精准打击非线性——SVM嵌入了尖端前沿的“高维映射”技术。高维度——SVM配备了“核函数”子装置,有效节省成本,轻便节能。关注结构风险——SVM装备风险自我识别系统,为驰骋疆场提供全面的保驾护航。另外,SVM与logistic都是线性分类器的一种,那么它们有什么区别和联系?线性分类器又到底是什么?2.线性分类器上次说到了SVM属于线性分类器的一种,什么是线性分类呢?在一个二维空间里,我们可以用一个线性函数来将样本点分开,如果一个线性函数能将样本点全部分开,则称这些数据是线性可分的,否则称为线性不可分。这个线性函数

  • 海量ICLR论文点评公开,用这几个工具可以读得更轻松

    允中李林编译整理 量子位出品|公众号QbitAINIPS2017开幕在即,这两天twitter上却在热火朝天地聊着还有点遥远的ICLR2018。因为,所有论文的评分和点评终于公开了!ICLR采用openreview的评审制度,所有论文会匿名公开在openreview网站上,接受同行们的匿名评分和提问。明年4月底举办的第6届ICLR总共收到了981篇论文,差不多是去年的2倍。截止12月1日,有979篇至少获得了一个评分。这么多论文……也难怪有学者在twitter上吐槽,说iclr这个时候放出评论,真是毁了学术界的周末/(ㄒoㄒ)/~~有博客统计了今年ICLR论文的评分情况,平均分是5.24,中位数是5.33:这位博主YaguangLi另外还统计了单篇论文最高分最低分的差异,有87%的论文,高低分差值小于3:但900多篇论文和评论,该从哪看起?这几个工具,也许能让你轻松一点。一是OpenReviewExplorer,可以搜索在标题和摘要中包含特定关键词的论文,然后将搜索结果按排名、评分排列。地址:https://chillee.github.io/OpenReviewExplorer/如果

  • 推荐:机器学习 Python库Top 20

    如今开源是创新的核心,推动着技术的飞速革新。本文会为你介绍2016年机器学习Top20Python开源项目,同时分析得出一些有趣的见解和发展趋势。KDnuggets为您带来Github上最新的Python机器学习开源项目前20名。奇怪的是,去年一些非常活跃的项目渐渐停滞了,因此没能上榜,而13个新项目冲进了今年的top20(参考贡献contributions和提交数commits)。2016Top20Python机器学习开源项目1.Scikit-learn是一个简单且高效的数据挖掘和数据分析工具,易上手,可以在多个上下文中重复使用。它基于NumPy,SciPy和matplotlib,开源,可商用(基于BSD许可)提交数:21486,贡献者:736,Github链接:Scikit-learn(http://github.com/scikit-learn/scikit-learn02.Tensorflow最初由谷歌机器智能科研组织中的谷歌大脑团队(GoogleBrainTeam)的研究人员和工程师开发。该系统设计的初衷是为了便于机器学习研究,能够更快更好地将科研原型转化为生产项目。提交数:

  • 2017年中国程序员调查分析:大数据备受欢迎

    在互联网行业,程序员一直是很受关注的人群。对准备步入社会的大学生们来说,程序员是一个比较热门的选择。大讲台老师根据2017年中国程序员调查的数据,给同学们好好介绍一下程序员的编程语言、薪酬范围等信息,让大家对程序员有个准确的认知,也方便以后的选择。 大讲台老师通过对北京、广东、浙江、上海等全国28个省的优秀开发者的调查信息,对程序员的年龄组成、性别比例、擅长的计算机语言、工作时间以及薪资等进行了统计和分析。(一)程序员地理分布从调查结果来看,有一半以上的程序员来自于北京(23.55%)、广东(16.53%)、浙江(12.81%)和上海(12.40%)。北上广作为中国经济和科技最为发达的地区,是程序员的主要聚集地。浙江杭州地区也吸引了一大批创业者,为程序员的就业和发展提供了优质条件。(二)程序员年龄组成结果显示,绝大部分程序员年龄都不到35岁。超过一半的程序员年龄在23-30岁之间。当然程序员中间的“天才少年”的比例也不低。(三)程序员性别比例一直以来,程序员这一群体主要是男性为主。在本次调查中发现,程序员群体中男女比例超过了12:1。如此“畸形”的性别组成,也解释了为什么很多程序员自嘲

  • 畅游数据库性能优化过程简析(上)

    前言经过周末两天的折腾,在大家的帮助下最终将用户DB的性能峰值由最初的不到8W的QPS+TPS提升至17W,心情也由最初的忐忑过渡到现在的平静,现在想来,整个的优化过程感觉还是比较好玩的,趁着现在还有些印象,就把整个排查&优化过程详细的记录下来,以备不时之需,也希望能给人一些启发来解决其它问题,同时,也让俺感谢一下在整个解决过程中给予很多帮助的同事,没有你们在背后的帮助,DB端解决问题的时间要更久!问题背景上周团队聚餐的时候,老大说有一个用户使用DB的时候遇到了问题,现有的DB性能无法满足用户的性能需求。用户在对现有的DB进行压力测试时发现QPS+TPS小于7W/S,继续加大压力的时候Load上涨、IdleCPU很低、Threadrunning飙升、性能下降,最终导致网站处理并发能力的下降,无法达到预期的吞吐量。用户在对现有逻辑及吞吐量计算的基础上提出了性能指标,即DB的单机性能QPS+TPS大于10W/S,只有这样才能满足业务要求,否则DB就是整个链路的瓶颈。由于用户的上线时间临近,上线压力比较大,老大说周末尽力搞定,如果搞不定,只能上最好的机器来解决性能问题,这样的话,成本

  • 大赛具体情况

      1.中国大学生计算机设计大赛   中国大学生计算机设计大赛(简称“大赛”或4C)启筹于2007年,始创于2008年,已经举办了14届68场赛事。大赛国赛的参赛对象覆盖中国大陆高等院校中所有专业的当年在校本科生(包括来华留学生)。大赛每年举办一次,国赛决赛时间在当年7月中旬至8月下旬。   参赛作品选题范围不限(除企业合作项目外),鼓励作品的创新性,也鼓励计算机技术在其他各专业中应用的选题,所提交作品应能充分展示学生的计算机应用能力。参赛作品归为以下六类:   (1)数据库应用系统   (2)Web网站设计   (3)多媒体制作(含虚拟实验、微课程)   (4)程序设计应用(含移动应用)   (5)人工智能应用(含大数据应用、物联网应用)   (6)企业合作项目(题目见大赛网站)   作品要求:  (1)学生在报名参赛时,根据项目的主要技术选择参赛类别。类别选择时请仔细阅读大赛各类别的评分标准(详见大赛网站)。  (2)鼓励在大赛作品中使用国产软件。  (3)参赛作品是学生在课程学习或自主学习的成果总结,应该由参赛队员独立完成。若引用开源代码和第三方工具,必须在设计说明书中详细说明开

  • 说一说Unsafe魔法类

    这篇算是对Unsafe的一个总体概况,由于内容实在太多,后续会分开几篇文章对里面内容展开细讲 前言 Unsafe可以说是java的后门,类似西游记中的如来佛祖法力无边,Unsafe主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。 从名字角度看Unsafe是不安全的意思,使用这个类要极度谨慎,因为乱用这个类会增加程序的出错概率变大,使得Java这种安全的语言变得不再“安全” Unsafe提供的API大致可分为 内存操作 CAS Class相关 对象操作 线程调度 系统信息获取 内存屏障 数组操作 基本 因为Unsafe是不安全的,所以它本身设计的时候也增加了使用者调用的难度。 //私有构造器 privateUnsafe(){ } //获取单例要检查调用者的类加载器是否是BootStrap @CallerSensitive publicstaticUnsafegetUnsafe(){ Classvar0=Reflection.getCallerClass

  • iOS7隐藏状态栏 statusBar

    转:http://blog.csdn.net/dqjyong/article/details/17896145  评:通过这点变化,可以看出苹果倾向于使用delegate取代全局变量。 IOS7中,不仅应用的风格有一定的变化,状态栏变化比较大,我们可以看到UIVIEWCONTROLLER的状态栏与导航栏基本是一体的。因此UIVIEWCONTROLLER的HIDE/SHOW状态的方法也跟其他版本的不一样了。在IOS7以前的版本,HIDE/SHOW是通过以下代码实现   [cpp] viewplaincopy   [[UIApplication sharedApplication] setStatusBarHidden:YES(NO) withAnimation:UIStatusBarAnimationSlide];   在iOS7中默认情况下,这个方法不成功了。到setStatusBarHidden:withAnimation:声明的头文件去看看,多了一句注释://Settingsta

  • R中矩阵运算

    #数据产生 #rnorm(n,mean=0,sd=1)正态分布的随机数(r代表随机,可以替换成dnorm,pnorm,qnorm作不同计算。r=random=随机,d=density=密度,p=probability=概率,q=quantile=分位) #runif(n,min=0,max=1)平均分布的随机数 #rep(1,5)把1重复5次 #scale(1:5)标准化数据 >a<-c(rnorm(5),rnorm(5,1),runif(5),runif(5,-1,1),1:5,rep(0,5),c(2,10,11,13,4),scale(1:5)[1:5]) >a [1]-0.412535560.12192929-0.47635888-0.971716531.091622431.87789657 [7]-0.117179372.929535221.33836620-0.032690260.875409200.13005744 [13]0.119006860.766639400.28407356-0.912511810.179979730.50452258 [19]

  • Azure Solution Design 配置管理系列(PART 6)

    AzureSolutionDesign配置管理系列(PART5) 选择虚拟网络、子网关闭主机诊断高级设置标记设置,方便查询、升级验证通过,完成主机创建! AzureSolutionDesign配置管理系列(PART7)

  • Appium Android 屏幕滑动

  • 单元测试之道Java版本读后感受

    一、第1章:单元测试   读完这本单元测试之道,我们首先要知道什么是单元测试?为什么要使用单元测试?如何进行单元测试?这些都是我们需要思考的。   单元测试是开发者编写的一小段代码,用于检验被测代码的一个很小的很明确的功能是否正确。单元测试不但会使我们的工作完成的更轻松,而且会令我们的设计变得更好,甚至大大减少我们花在调试上的时间。单元测试首先要考虑的是在编写这些测试方法之前,如何测试这些可疑的方法;接着我们需要运行测试本神忙活着同时运行系统模块的所有其他测试,甚至如果测试运行的比较快我们可以运行整个系统的测试,及时在测试过程中,我们需要确认每个测试是否通过,但是我们会因此养成一个习惯,快速看出代码到底是否正确的习惯。 二、第4章:测试哪些内容 为了提高我们的测试技巧,我们主要将之的测试的地方分为6点: Right--结果是否正确?   B--是否所有边界条件都正确?I--检查反向关联 不一致的输入数据 格式错误 空值或者不完整的值 与合理值相差很大的数值 I--检查反向关联 C--运用其他手段交叉检查结果 E--是否可以强制错误条件发生? P--是否满足性能

  • 手机号限制

    限制input输入框只能输入纯数字 1、onkeyup="value=value.replace(/[^\d]/g,'')"复制 使用onkeyup事件,有bug,那就是在中文输入法状态下,输入汉字之后直接回车,会直接输入字母 2、onchange="value=value.replace(/[^\d]/g,'')"复制 使用onchange事件,在输入内容后,只有input丧失焦点时才会得到结果,并不能在输入时就做出响应 3、oninput="value=value.replace(/[^\d]/g,'')"复制 使用oninput事件,完美的解决了以上两种问题,测试暂时还没有出现其它问题。 <inputtype="text"maxlength="11"oninput="value=value.replace(/[^\d]/g,'')"placeholder="请输入您的手机号">复制 js进行验证             varphone_reg=/^13[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|18[0-9]{1}[

  • Blender如何设置中文界面

    废话不多说,上图 bingo!!

  • RyuJIT的华丽转身【译文】

      2018-06-19   RyuJIT是作为.NET即时编译器的代号称谓,它是.NET运行时的基本组件之一。与此相反的是,Roslyn作为C#编译器,其编译C#代码成为IL字节码。然后,其再将IL字节码编译成相对于多种处理器的机器码。   随着最近对dotnet/coreclr#18064的合并,将生成组件的遗留代码(来自较老的JIT实现)从RyuJIT的源码中进行了移除。这个版本删除了近5万行代码!现在,四种处理理体系结构(x86、x64、ARM32、ARM64)可完全基于RyuJIT架构。   回顾一下关于RyuJIT短暂的历史,以及我们是如何做到现在这样的,是一件很有趣的事情。   RyuJIT架构的设计开始于9年前,而着手实现开始于7年前。RyuJIT是现有的JIT32编译器(它支持x86和ARM32)的进化版实现,并逐步用一个新的寄存器分配器和代码生成器替换了编译器的大部分“后端”,并入了许多新的和改进的“前端”优化组件。在向新的代码生成体系结构过渡的过程中,我们将旧代码与之结合。这样做提供了好处,但是在测试和维护成本方面,以及开发人员需要处理由大量的分散的遗留代码的困惑

相关推荐

推荐阅读