2022-02-22_星期二

消息队列高手课

请内存的逻辑:

  1. 计算要创建对象所需要占用的内存大小
  2. 在内存中找一块儿连续并且是空闲的内存空间,标记为已占用
  3. 把申请的内存地址绑定到对象的引用上,这时候对象就可以使用了

现代的 GC 算法大多采用的是“标记 - 清除”算法或是它的变种算法,这种算法分为标记和清除两个阶段:

  1. 标记阶段:从 GC Root 开始,你可以简单地把 GC Root 理解为程序入口的那个对象,标记所有可达的对象,因为程序中所有在用的对象一定都会被这个 GC Root 对象直接或者间接引用。
  2. 清除阶段:遍历所有对象,找出所有没有标记的对象。这些没有标记的对象都是可以被回收的,清除这些对象,释放对应的内存即可。

这个算法有一个最大问题就是,在执行标记和清除过程中,必须把进程暂停,否则计算的结果就是不准确的。

垃圾回收完成后,还需要进行内存碎片整理,将不连续的空闲内存移动到一起,以便空出足够的连续内存空间供后续使用。

在高并发的情况下,一切都变得不一样了:

我们的程序会非常繁忙,短时间内就会创建大量的对象,这些对象将会迅速占满内存,这时候,由于没有内存可以使用了,垃圾回收被迫开始启动,并且,这次被迫执行的垃圾回收面临的是占满整个内存的海量对象,它执行的时间也会比较长,相应的,这个回收过程会导致进程长时间暂停

进程长时间暂停,又会导致大量的请求积压等待处理,垃圾回收刚刚结束,更多的请求立刻涌进来,迅速占满内存,再次被迫执行垃圾回收,进入了一个恶性循环。如果垃圾回收的速度跟不上创建对象的速度,还可能会产生内存溢出的现象。

降低垃圾回收频率的方法:

  • 最有效的方法就是,优化你的代码中处理请求的业务逻辑,尽量少的创建一次性对象,特别是占用内存较大的对象
    • 如:把收到请求的 Request 对象在业务流程中一直传递下去,而不是每执行一个步骤创建一个内容和 Request 对象差不多的新对象
  • 对于需要频繁使用,占用内存较大的一次性对象,我们可以考虑自行回收并重用这些对象
    • 线程池

后端技术面试 38 讲

面向对象编程语言有三大特性:封装、继承、多态

通俗地说,接口(抽象类)的多个实现就是多态

多态可以让程序在编程时面向接口进行编程,在运行期绑定具体类,从而使得类之间不需要直接耦合,就可以关联组合,构成一个更强大的整体对外服务。绝大多数设计模式其实都是利用多态的特性玩的把戏,开闭原则和依赖倒置原则也是利用多态的特性。正是多态使得编程有时候像变魔术,如果能用好多态,可以说掌握了大多数的面向对象编程技巧。

封装是面向对象语言提供的特性,将属性和方法封装在类里面。

里氏替换原则

有一个关于继承的设计原则,叫里氏替换原则。

这个原则说:若对每个类型 T1 的对象 o1,都存在一个类型 T2 的对象 o2,使得在所有针对 T2 编写的程序 P 中,用 o1 替换 o2 后,程序 P 的行为功能不变,则 T1 是 T2 的子类型。

  • 通俗地说就是:子类型必须能够替换掉它们的基类型。
  • 再稍微详细点说,就是:程序中,所有使用基类的地方,都应该可以用子类代替。

继承是否合理我们需要用里氏替换原则来判断:

继承是否合理并不是从继承的设计本身看,而是从应用场景的角度看。如果在应用场景中,也就是在程序中,子类可以替换父类,那么继承就是合理的,如果不能替换,那么继承就是不合理的。


当子类继承父类的时候,根据里氏替换原则,使用者可以在使用父类的地方使用子类替换,那么从契约的角度,子类的契约就不能比父类更严格,否则使用者在用子类替换父类的时候,就会因为更严格的契约而失败。

在类的继承中,如果父类方法的访问控制是 protected,那么子类 override 这个方法的时候,可以改成是 public,但是不能改成 private。因为 private 的访问控制比 protected 更严格,能使用父类 protected 方法的地方,不能用子类的 private 方法替换,否则就是违反里氏替换原则的。

实践中,当你继承一个父类仅仅是为了复用父类中的方法的时候,那么很有可能你离错误的继承已经不远了。一个类如果不是为了被继承而设计,那么最好就不要继承它。粗暴一点地说,如果不是抽象类或者接口,最好不要继承它。

如果你确实需要使用一个类的方法,最好的办法是组合这个类而不是继承这个类,这就是人们通常说的组合优于继承

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Class A{
 public Element query(int id){...}
 public void modify(Element e){...}
}

Class B{
  private A a;
  public Element select(int id){
    a.query(id);
  } 
   public void modify(Element e){
     a.modify(e);
   }
}

这其实就是对象适配器模式了,使用这个模式的话,类 B 不需要继承类 A,一样可以拥有类 A 的方法,同时还有更大的灵活性,比如可以改变方法的名称以适应应用接口的需要。

断舍离

你的圈子越广,就越容易生活在别人的生活中;你需要的东西越多,就越容易迷失在物品之中。 经常有人盲目攀比效仿他人的生活,或者在购物季冲动地买买买,其实这都是对自己真正的需求认知不够,心中混乱的执念往往也会映照在生活环境中。

断舍离注重“空间”,即以空间为主体核心的思维方式——空间轴。

“为确保空间的干净整洁,而将物品量尽可能地缩减成最适合的量。“这种思维是实践断舍离不可或缺的。

常常抱怨“还是无法放手…”的人大致有以下 3 类:

  1. 逃避现实型
  2. 执着过往型
  3. 忧虑未来型

这三种类型的人共通的一点就是“对时间的意识比较淡薄”。

断舍离,不是要求人没随意地“弃”,而是把“舍”作为解决问题的方法之一。

我会再三地告诉今后准备努力实践“断舍离” 的人:

  • 如果你不想再吃了,如果肚子己经吃得饱饱的,那就应该放下碗筷,不多吃也没问题。因为,吃不吃饭我做主。
  • 如果你不想再穿了,如果这件衣服己经让你厌烦了那就应该脱下衣服,不穿也没问题。因为,穿不穿我做主。

我们为什么睡觉

我建议老年人进行两项改变:

  1. 在户外晨练时戴上太阳镜
  2. 下午晚些时候到户外进行阳光照射不戴太阳镜

对年轻人或中年人来说,褪黑激素在除时差以外的情況下并没有被证明能有效帮助睡眠,而与之不同的是,褪黑激素处方己被证明有助于增强老年人的昼夜节律和与之相关的褪黑激素节律,减少入睡所花费的时间,改善使用者感受到的睡眠质量,以及提升早上的清醒度等。

随着个体年龄的增长,大脑并不会均匀同步地退化。相反,大脑的某些部分比其他部分开始丢失神经元的时间要早的多,这个过程称为萎缩。 衰老程度最严重的大脑区域正是产生深度睡眠的额叶中央区域。

老年人的记忆力差和睡眠不好不是巧合,而是相互关联的。

睡眠差是导致老年人认知和健康问题的最受重视的因素,这些问题包括糖尿病、抑郁症、慢性疼痛、中风、心血管疾病和阿尔茨海默病等。

睡眠是全球人们的健康保障:无论身体疾病还是精神疾病,睡眠总是会给出响应的处方。

莎士比亚预言睡眠是“人生筵席上主要的滋补品”。

睡眠的每个阶段在夜间不同的时间为大脑提供不同的益处。因此,没有某种形式的睡眠比另一种更重要的说法。失去其中的任何一种睡眠,都会导致脑损伤。

睡眠已经一次又一次地证明了自己是记忆的帮手:在学习之前让你的大脑做好准备开始创造新的记忆,并在学习之后巩固这些记忆,防止遗忘。

海马体是深藏在两侧大脑中的一个长长的手指形结构,它提供了一个短期的存储库,或者叫临时信息库,用于积累新的记忆。

睡眠的电信号交易正在暗中进行:将基于事实的记忆以临时存储仓库 (海马体)转移到长期安全的保险库(大脑皮层)。

一个人在晚上的睡眠纺锤波越多,第二天早上的学习能力就恢复得越多。

非快速眼动睡眠纺锤波尤其在清晨时分特别集中,夹在较长时间的快速眼动睡眠之间。如果只睡6个小时或更少,你就会缩减通常由睡眠纺锤波为大脑带来的学习能力恢复的福利。

睡眠对于学习的 2 个好处:

  1. 学习之前的睡眠,可以刷新我们初步形成新记忆的能力
  2. 学习之后,它可以有效地点击这些新创建的文件上的“保存”按钮

与相同的清醒时间相比,睡眠提供的记忆保存效率要高出 20%到 40%。

在提供优越的记忆力存储方面,与后半夜丰富的快速眼动睡眠相比,前半夜充满深度非快速眼动的睡眠胜出了。

updatedupdated2022-03-092022-03-09