内存碎片

Redis百亿级Key存储方案

岁酱吖の 提交于 2020-02-04 23:53:14
1 需求背景 该应用场景为DMP缓存存储需求,DMP需要管理非常多的第三方id数据,其中包括各媒体cookie与自身cookie(以下统称supperid )的mapping关系,还包括了supperid的人口标签、移动端id(主要是idfa和imei)的人口标签,以及一些黑名单id、ip等数据。 在hdfs的帮助下离线存储千亿记录并不困难,然而DMP还需要提供毫秒级的实时查询。由于cookie这种id本身具有不稳定性,所以很多的真实用户的浏览行为会导致大量的新cookie生成,只有及时同步mapping的数据才能命中DMP的人口标签,无法通过预热来获取较高的命中,这就跟缓存存储带来了极大的挑战。 经过实际测试,对于上述数据,常规存储超过五十亿的kv记录就需要1T多的内存,如果需要做高可用多副本那带来的消耗是巨大的,另外kv的长短不齐也会带来很多内存碎片,这就需要超大规模的存储方案来解决上述问题。 2 存储何种数据 人⼝标签主要是cookie、imei、idfa以及其对应的gender(性别)、age(年龄段)、geo(地域)等;mapping关系主要是媒体cookie对supperid的映射。以下是数据存储⽰示例: 1) PC端的ID: 媒体编号-媒体cookie=>supperid supperid => { age=>年龄段编码,gender=>性别编码,geo=

Redis百亿级Key存储方案

依然范特西╮ 提交于 2020-02-04 23:51:32
原标题:Redis百亿级Key存储方案 1 需求背景 该应用场景为AdMaster DMP缓存存储需求,DMP需要管理非常多的第三方id数据,其中包括各媒体cookie与自身cookie(以下统称admckid)的mapping关系,还包括了admckid的人口标签、移动端id(主要是idfa和imei)的人口标签,以及一些黑名单id、ip等数据。 在hdfs的帮助下离线存储千亿记录并不困难,然而DMP还需要提供毫秒级的实时查询。由于cookie这种id本身具有不稳定性,所以很多的真实用户的浏览行为会导致大量的新cookie生成,只有及时同步mapping的数据才能命中DMP的人口标签,无法通过预热来获取较高的命中,这就跟缓存存储带来了极大的挑战。 经过实际测试,对于上述数据,常规存储超过五十亿的kv记录就需要1T多的内存,如果需要做高可用多副本那带来的消耗是巨大的,另外kv的长短不齐也会带来很多内存碎片,这就需要超大规模的存储方案来解决上述问题。 2 存储何种数据 人⼝标签主要是cookie、imei、idfa以及其对应的gender(性别)、age(年龄段)、geo(地域)等;mapping关系主要是媒体cookie对admckid的映射。以下是数据存储⽰示例: 1) PC端的ID: 媒体编号-媒体cookie=>admckid admckid => { age=>年龄段编码

JVM 完整深入解析

末鹿安然 提交于 2020-02-04 22:17:58
工作之余,想总结一下JVM相关知识。 Java运行时数据区: Java虚拟机在执行Java程序的过程中会将其管理的内存划分为若干个不同的数据区域,这些区域有各自的用途、创建和销毁的时间,有些区域随虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束来建立和销毁。Java虚拟机所管理的内存包括以下几个运行时数据区域,如图: 1、程序计数器:指向当前线程正在执行的字节码指令。线程私有的。 2、虚拟机栈:虚拟机栈是Java执行方法的内存模型。每个方法被执行的时候,都会创建一个栈帧,把栈帧压人栈,当方法正常返回或者抛出未捕获的异常时,栈帧就会出栈。 (1)栈帧:栈帧存储方法的相关信息,包含局部变量数表、返回值、操作数栈、动态链接 a、局部变量表:包含了方法执行过程中的所有变量。局部变量数组所需要的空间在编译期间完成分配,在方法运行期间不会改变局部变量数组的大小。 b、返回值:如果有返回值的话,压入调用者栈帧中的操作数栈中,并且把PC的值指向 方法调用指令 后面的一条指令地址。 c、操作数栈:操作变量的内存模型。操作数栈的最大深度在编译的时候已经确定(写入方法区code属性的max_stacks项中)。操作数栈的的元素可以是任意Java类型,包括long和double,32位数据占用栈空间为1, 64 位数据占用2。方法刚开始执行的时候,栈是空的,当方法执行过程中

JVM第一弹

微笑、不失礼 提交于 2020-02-04 11:56:09
JVM第一弹 基本概念 JVM是可运行java代码的假想计算机,包括一套字节码指令集,一组寄存器,一个栈,一个垃圾回收、堆和一个存储方法域。JVM是运行在操作系统之上的,它与硬件没有直接的交互。 运行过程 我们都知道Java代码源文件,通过编译器能够产生相应的.Class字节码文件,而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码。 ① Java源文件 ——> 编译器 ——> 字节码文件 ② 字节码文件 ——> JVM ——> 机器码 每种平台的解释器是不同的,但是虚拟机是相同的,这也就是java为什么能够跨平台的原因了。当一个程序从开始运行,这时虚拟机就开始实例化了,多个程序 启动就会存在多个虚拟机实例。 程序退出或者关闭,则虚拟机实例消亡,多个虚拟机实例之间数据不能共享。 类加载器 什么是类的加载? 类的加载是指将类的字节码文件数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。 类的加载的最终产品是位于堆区内中的Class对象,Class对象封装了类在方法区内的数据结构,并且向java程序员提供了访问方法区内的数据结构的接口。 类加载器包括: 启动类加载器(BootStrap) ——主要有C++进行实现的。用来加载jdk安装目录下的:jre/lib下的可执行jar包。

AJ整理问题之:内存堆栈

谁说胖子不能爱 提交于 2020-02-04 05:47:49
内存 数据在内存中的存放 在计算机中,运行的应用程序的数据都是保存在内存中的。 不同类型的数据,保存的内存区域不同,其中包括: 1:栈区(stack)由编译器自动分配并释放,一半存放函数的参数值,局部变量等。 2:堆区(heap)由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收。 3:全局区(静态区)全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。 上面三个很重要,下面三个了解 4:文字常量区:存放常亮字符串,程序结束后由系统释放。 5:程序代码区:存放函数的二进制代码。 6:寄存器去:用来保存栈顶指针和指令指针(我们基本用不到。。。)。 栈内存区中得数据 栈区内存是压栈的讲究 特点:先进后出。 系统给自动回收。 由系统自动分配,速度较快。但程序员是无法控制的。 int sum(int x, int y) { NSLog(@"x: %p, Y: %p", &x, &y); int result = x + y; NSLog(@"%p", &result); return result; } void demo1() { // 在栈区中的变量,i本质上对应"内存地址"的"标签" // 指针 * 表示指向内容空间的内容 & 表示地址 int i = 10; i =

堆和栈的概念

十年热恋 提交于 2020-02-04 05:45:50
数据在内存中的存放 在计算机系统中,运行的应用程序的数据都是保存在内存之中。 不同类型的数据,保存的内存区域不同,其中包括: 1.栈区:(stack)由编译器自动分配并释放,一般存放函数的参数值,局部变量等。 2.堆区:(heap)由程序猿分配和释放,如果程序猿不释放,程序结束时,可能由操作系统回收。 3.寄存器区:用来保存栈顶指针和指令指针。 4.全局区(静态区):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。 5.文字常量区:存放常量字符串,程序结束后由系统释放。 6.程序代码区:存放函数的二进制代码。 栈区中的数据 应用程序启动后,操作系统会为应用程序在栈区开辟内存空间,用于存放局部变量,以及函数的参数等。 iOS主线程栈区大小为1M,MAC主线程栈区大小为8M. 栈区中的变量由编译器负责分配和释放。 栈区中的数据是以“栈”的形式管理的,先进后出(FIBO)。 访问栈区中变量的效率高,不会出现内存碎片。 栈区中的变量名(不带*)相当于是指向栈区数据的指针别名,变量名可以简化程序员的工作。 栈中地址是从高地址——>低地址。 堆中的数据 由于栈区的空间有限,iOS的应用程序中,对象都是建立在堆中的。 堆区包括系统内存和虚拟内存(硬盘内存),由所有正在运行的应用程序共享使用。

JVM的认识

不问归期 提交于 2020-02-03 22:08:56
一、概念   JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个 虚构出来 的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 引入Java语言虚拟机后,Java语言在 不同平台上运行时不需要重新编译 。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。 二、概述 Java虚拟机有自己 完善的硬件架构 ,如处理器、堆栈等,还具有相应的指令系统。 Java虚拟机本质上就是一个 程序 ,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“ 一次编译,多次运行 ”。 Java技术使同一种应用可以运行在不同的平台上。Java平台可分为两部分,即J ava虚拟机 (Java virtual machine,JVM)和 Java API类库 三、体系结构 Java虚拟机主要分为五大模块: 类装载器子系统 、 运行时数据区 、 执行引擎 、 本地方法接口 和 垃圾收集模块。 Java虚拟机不是真实的物理机,它没有寄存器,所以指令集是使用

Java知识之JVM

…衆ロ難τιáo~ 提交于 2020-02-03 21:22:31
类加载器 类装载器ClassLaoder负责加载class文件,class文件开头有特定的文件标识,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则有Execution Engine决定虚拟机自带的类加载器 引导类加载器 这个类加载使用C/C++与亚伯实现的,嵌套在JVM内部,它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类 并不继承自java.lang.ClassLoader,没有父加载器 加载扩展类和应用程序类加载器,并指定未他们的父类加载器,处于安全考虑,Bootstrap启动类加载器只加载包名未java、javax、sun等开头的类 扩展类加载器 Java语言编写 派生于ClassLoader类 父类加载器为启动类加载器 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext,子目录下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载 应用类加载器 java语言编写 派生于ClassLoader类 父类加载器为扩展类加载器

Lua源码分析 - 数据结构篇 - Mem内存操作

a 夏天 提交于 2020-02-03 04:06:32
原先以为Lua的内存操作也是高大上的,但是仔细研究了一下,突然发现,这块代码绕来绕去,封装来封装去,有一些low low感。 废话少说,直接上原理吧。这部分的代码,我也不画详细的图了。 Mem内存操作 - 核心分配函数 Lua的全局状态机里面,有两行代码,定义了内存分配的基础函数。底层的内存分配函数主要调用了c语言本身的内存分配函数(malloc、free、realloc等)。想要研究linux系统的内存分配器的,可以看我这边文章 《Linux c 开发 - 内存管理器ptmalloc》 先看一下全局状态机里面的定义: /* ** 'global state', shared by all threads of this state ** lua 全局状态机 ** 作用:管理全局数据,全局字符串表、内存管理函数、 GC 把所有对象串联起来的信息、内存等 */ typedef struct global_State { /* 版本号 */ const lua_Number *version; /* pointer to version number */ /* 内存管理 */ lua_Alloc frealloc; /* Lua的全局内存分配器,用户可以替换成自己的 - function to reallocate memory */ void *ud; /*

C++面试

泪湿孤枕 提交于 2020-02-02 14:31:08
vector中v[i]和v.at(i)的区别 v[5]; //A v.at[5]; //B 如果v非空,A和B没有任何区别。如果v为空,B会抛出std::out_of_range异常。 c++标准不要求vecor<T>::operator[]进行下标越界检查,原因是为了提高效率。如果需要下标越界检查,使用at。但性能会受到影响,因为越界检查增加了性能开销。 vector扩容原理 新增元素:vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素; 对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了; 初始时刻vector的capacity为0,塞入第一个元素后capacity增加为1; 不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容 哪些函数不能成为虚函数? 不能被继承的函数和不能被重写的函数。 1.普通函数 2.友元函数 3.构造函数 4.内联成员函数 5.静态成员函数 溢出 1.栈溢出(栈的大小通常是1M-2M) 栈溢出是指函数中的局部变量造成的溢出(注:函数中形参和函数中的局部变量存放在栈上) 栈溢出包含两种情况:1.分配的的大小超过栈的最大值,2.分配的大小没有超过最大值,但是分配的buff比接收buff小