-------------------------------------C++------------------------------------------------
函数参数 值传递 和 地址传递 的不同. 值传递形参不能修饰实参;地址传递形参会修饰实参。引用传递也会改变
函数返回值用引用的时候,不要返回局部变量的引用
32位操作系统下,指针占4个字节空间;64位下,占8字节空间
//new 开辟内存空间
int * arr = new int[10];
for(int i=0; i<10; i++) {
arr[i] = i+100;
}
//delete 删除内存;如果是数组 用 delete[]
delete[] arr;
值传递类对象会复制一份,调用拷贝构造;值返回局部对象的时候也会复制一份
浅层拷贝 vs 深层拷贝:指针指向的堆内存;有堆内存分配,就要用深层拷贝
static 成员,在全局区内存分配。类内声明;类外初始化
类的 成员变量 与 成员函数 分开存储。只有 非静态成员变量 在对象内存上
引用 实际是指针常量; 对引用的操作相当于直接操作真名本身;引用与真名共地址,没有额外分配空间,指针需要额外4字节的空间;引用必须初始化,指针不用初始化
this指针 是指针常量,指向固定,但指向的值可修改;
常函数 是相当于 const this ,this指向的值也不能修改; mutable 关键字修饰的变量,可在常函数中修改
父类中所有非静态成员都被子类继承;但父类的private成员,子类不能访问
子类同名函数会隐藏父类的同名函数;加作用域访问父类同名函数
ofstream写 ifstream读 fstream读写文件
函数模板 template<> 要能推导出一致的类型才行;普通函数可以自动类型推导,模板函数不行
字符串赋值要用 strcpy, 不能直接用 =
字符串指针申请内存长度 (length+1)
字符串处理函数,传入字符串,不能是字符数组, strcmp(str1,str2);
memset()是基于内存字节写值
char * 是指针 string 是C++风格的类,类内部封装了 char*
string 扩展是开辟新地址复制扩展,原地址释放
string类中有一个指向动态数组的指针,拷贝构造函数是 深拷贝
string和vector容qi 都有三个指针 start finsh end
函数指针,应用于回调函数 统一接口,实现面向对象,(线程创建有一个函数指针)
函数名代表函数指针,函数名取地址充当函数指针
typedef 给类型起别名
typedef int(*PFUN)(int,int); //给函数指针起别名
智能指针 管理堆对象的生命周qi。uniq_ptr 独享;share_ptr 引用计数;weak_ptr 不影响计数
右值引用 && 移动语义 move()把资源移动给另一个变量;拷贝语义是开辟空间复制过去,效率低。移动构造和移动赋值函数
注意初始化跟赋值的不同
auto 自动类型推导
thread对象 不能拷贝,不能赋值,但可以交换,可以转移
void* 代表任意数据类型:指针、变量
结构体由于内存对齐,定义的时候从小到大定义成员
结构体嵌套,用剥洋葱方式访问
结构体指针的赋值,先分配内存,用copy方式到堆内存;深copy
结构体包含指向自身的指针,next指向 struct Node类型变量的地址
虚函数深入理解,当基类经过重重继承,拥有许多子孙类之后,他们的共有方法还能保持同样的签名
空的结构体占内存 一个字节
虚函数 用 virtual 修饰的,用虚函数指针vfptr,虚函数表
虚函数内存模型
static作用:
类中的static主要用于创建静态成员变量、静态成员函数与静态局部变量。普通的成员变量使用static修饰就是静态成员变量。这种静态成员变量需要类内声明,类外初始化。静态成员函数没有this指针,因此不能调用非静态成员(非静态成员变量和成员函数)。
使用static修饰的局部变量就是静态局部变量。静态局部变量所在的代码块被第一次调用时,静态局部变量内存开辟,与非静态局部变量不同的是,代码块调用完成后,静态局部变量不会被销毁,下次代码被调用时,继续使用之前的静态局部变量,直到程序运行终止后才会被自动销毁。
const作用:
const修饰的成员函数,称为常成员函数。
const修饰对象,表示该对象是一个常量对象。
const修饰的成员变量,表示常成员变量。
const修饰局部变量,表示局部变量不可变,通常用于引用类型的函数参数。
extern”C” 的作用
我们可以在C++中使用C的已编译好的函数模块,这时候就需要用到extern”C”。也就是extern“C” 都是在c++文件里添加的。
extern在链接阶段起作用(四大阶段:预处理--编译--汇编--链接)。
I/O
write 是系统调用,类unix系统的系统调用函数, fwrite是c 标准io库函数, fwrite函数可移植。
write没用缓存, 这么说也不准确, 它和硬件之间是有buffer的,只是这个buffer是在内核态。
fwrite 有一个 用户态缓存, 并且, 这个缓存大小不可改变。 貌似 fctl函数可以改,但是这个方式不通用,windows系统上不可用。 于是区别就在于缓存了。
对于写日志这样的,频繁写短内容的 行为, 显然 有buffer 能提升性能。 因为它减少了访问磁盘的次数, 而访问磁盘的时间与访问内存差了几个数量级。 上边说了, C FILE 的缓存大概1k-4K, 我怀疑是4K, 因为一个page是4k。 对于printf这样的函数来说,是优化了, 但是对于 一次写入4k以上,频繁写入的操作, C FILE性能是不行的。 可以基于 write, 自己实现一个buffer 可变的 文件类封装。
发起数据读取的流程如下:
用户进程通过 read() 函数向 Kernel 发起 System Call,上下文从 user space 切换为 kernel space。
CPU 利用 DMA 控制器将数据从主存或硬盘拷贝到 kernel space 的读缓冲区(Read Buffer)。
CPU 将读缓冲区(Read Buffer)中的数据拷贝到 user space 的用户缓冲区(User Buffer)。
上下文从 kernel space 切换回用户态(User Space),read 调用执行返回。
用户程序发送网络数据的流程如下:
用户进程通过 write() 函数向 kernel 发起 System Call,上下文从 user space 切换为 kernel space。
CPU 将用户缓冲区(User Buffer)中的数据拷贝到 kernel space 的网络缓冲区(Socket Buffer)。
CPU 利用 DMA 控制器将数据从网络缓冲区(Socket Buffer)拷贝到 NIC 进行数据传输。
上下文从 kernel space 切换回 user space,write 系统调用执行返回。
页缓存读取策略:
当进程发起一个读操作 (比如,进程发起一个 read() 系统调用),它首先会检查需要的数据是否在页缓存中:
如果在,则放弃访问磁盘,而直接从页缓存中读取。
如果不在,则内核调度块 I/O 操作从磁盘去读取数据,并读入紧随其后的少数几个页面(不少于一个页面,通常是三个页面),然后将数据放入页缓存中。
页缓存写策略:当进程发起 write 系统调用写数据到文件中,先写到页缓存,然后方法返回。此时数据还没有真正的保存到文件中去,Linux 仅仅将页缓存中的这一页数据标记为 “脏”,并且被加入到脏页链表中。
然后,由 flusher 回写线程周期性将脏页链表中的页写到磁盘,让磁盘中的数据和内存中保持一致,最后清理“脏”标识。
在以下三种情况下,脏页会被写回磁盘:
空闲内存低于一个特定阈值。
脏页在内存中驻留超过一个特定的阈值时。
当用户进程调用 sync() 和 fsync() 系统调用时。
----------------------------------------Java--------------------------------------------------
Java 中 对象赋值是Reference赋值;基本类型是值传递
Java中将实参传递给方法(或函数)的方式是值传递 如果参数是基本类型的话,很简单,传递的就是基本类型的字面量值的拷贝,会创建副本。 如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,同样也会创建副本。
子类的构造函数中,编译器默认插入 super()父类的无参构造; 如果自己写了super,编译器就不自动加了
final 方法 不能被覆写;final 类 不能被继承 ; 常量池,赋值操作跟new的区别
自动装箱 自动拆箱;
不可变对象:一旦创建就不能修改。八个基本型别的包装类,String BigInteger BigDecimal
只要是对象,函数调用都是传指针;不可变对象只读,线程安全,并发读提高性能
死锁,互相持有对方需要的锁;守护线程跟main函数线程,同时结束,不要轻易持有资源
多线程同步;生产者和消费者模型; 信号量 countDownlatch Barrer; Timer定时任务,Quartz定时任务调度
NIO非阻塞IO AIO异步非阻塞IO Netty 三方异步IO框架
7.8 开始Java高阶的学习 同时学习 JNI
for-each enum枚举 不定项参数(可变参数)要位于最后
创建对象的方式:new clone 序列化 反射
函数式接口,只有一个未实现方法。Object所属的接口排除
方法引用 System::out
Stream流
字节码;类加载,双亲委派机制,SPI
JVM内存管理: 栈,栈帧,方法区,堆
动态代理应用
final class 是Java中定义一个不可被继承的类,也就是说不能再有子类。final class可以防止被继承和修改,保证类的安全性和稳定性。对于类和方法,final表示不能被继承或重写,对于成员变量,final表示常量,即只能被初始化一次。
对象重写 equals()就一定要重写hashcode()方法。因为跟散列集合一块工作,先判断hashcode是否相同,不同再看equals是否相同
hashmap 当元素超过 16*负载因子(0.75)就扩容,扩一倍,重新计算hash值; 桶超过8,容量超过64,链表转换为红黑树
扩容会重新hash会耗性能,尽量避免
用户线程,守护线程;用户线程执行完,进程就结束。线程状态:新建、就绪、阻塞、等待、结束
使用join() 插队,控制三个线程 1 2 3顺序执行
jmm java内存模型;并发编程三特性:原子、可见、有序。
GCRoots有哪些?
1.虚拟机栈(栈帧中的本地变量表)中引用的对象;
2.方法区中的静态变量;
3.方法区中常量引用的对象;比如:字符串常量池里的引用。
4.本地方法栈中 JNI引用的对象;
5.正在运行的线程。