精华内容
下载资源
问答
  • 部分代码会有“代码补完”字样的注释,原文是留给读者自己...elo值反映了支队伍在常规赛的胜场期望,1800的对应期望是获胜67场以上,就是王朝级强队了。具体的天梯分段分布如下:ELO值 匹配战绩 对应队伍描述18...

    部分代码会有“代码补完”字样的注释,原文是留给读者自己补完并在线评测的,相当于小作业,这里就请大家自行脑补吧。

    01. elo值

    elo值就像现在竞技网游里的天梯系统,队伍在每场比赛后会根据表现有所调整,胜增败减,小胜小增,大胜大增。elo值反映了一支队伍在常规赛中的胜场期望,1800的对应期望是获胜67场以上,就是王朝级强队了。具体的天梯分段分布如下:

    ELO值 匹配战绩 对应队伍描述

    1800 67-15 史诗级别

    1700 60-22 总冠军争夺者

    1600 51-31 季后赛水平

    1500 41-41 平均水平

    1400 31-51 乐透水平

    1300 22-60 无言以对

    1200 15-67 糟糕透顶

    历史上最高纪录是96年总决赛阶段的公牛,曾一度突破了1850分。

    知名数据分析网站538(fivethirtyeight.com)提供了NBA历史赛程的elo值记录(至2015赛季),有六万余条数据。这个数据量不能算很大,但是在本地用Excel直接打开操作,估计体验还是挺痛苦的,这里就介绍一下如何用Python+SQL来处理,或许会对广大劳形于Excel之间的朋友们有所帮助。

    02. 元组

    元组(tuple)是另一种Python中常用的数据类型,他跟列表非常相似,都可以包含若干元素,并且元素的调用都是通过方括号[]+索引的形式。

    sample_list = [0,1,2,3]

    sample_tuple = (0,1,2,3)

    # 列表的第1个元素

    sample_list[0]

    # 元组的第2个元素

    sample_tuple[1]

    主要区别在于:元组用括号()定义,列表用方括号[]定义

    元组不可更改

    即使只有一个元素,也需要有逗号,如(item1, )。如果缺了这个逗号,得到的仍是元素本身,而不是元组。

    元组只能在定义时赋值,如果强行更改会得到解释器的错误提示。

    TypeError:

    'tuple' object does not support item assignment

    有的函数返回值并非一个数值或字符,而是具有多重输出,这时就以元组格式存在。比如下例返回的是两个输入参数的和与乘积,可以点击运行查看,两个输出在()中。

    def sum_times(x, y):

    return (x + y), (x * y)

    sum_times(2,3)

    03. 数据库

    在之前的几篇教程中,我们已经接触过了一些数据集,既有在程序中生成的,也有存储在文本文件中的。对于体积较大的数据集,一般都存在文件中,程序运行时再读入内存。

    但是文件存储数据(.txt或.csv)还面临很大的问题,一是当数据量比计算机内存还要大的时候,会带来沉重的计算负担甚至无法运行;二是数据有可能高频变化,比如电商在双11高峰期每秒就有几万次交易,普通的文件格式显然无法处理。

    于是数据库(database)应运而生。数据库首先是结构化(structured)存储数据的方式,为了更加灵活的处理数据,程序不再一次性将所有数据读入内存,而是根据具体需要进行查询(query),获得相应的数据集。完成这些工作的程序语言叫作SQL(Structured Query Language),在计算机方面稍有常识的朋友想必都对这个缩写不会陌生。

    著名的关系型数据库管理系统有MySQL, Oracle等。

    04. SQLite

    SQL是专为查询、操作数据库所用的语言,所以不像Python, JavaScript等语言那样功能丰富,扩展多样。

    一个数据库由若干个表(table)组成,就像每个Excel文件里有多个Sheets。每个表又包含行(row)与列(column),这就比较好理解了。一行代表一个样本,而多列定义了各个维度上的属性。

    SQLite是一种轻型的数据库管理系统,占用资源极低且处理速度快,目前更新到了3版本。Python有专门处理SQLite语句的库sqlite3。

    import sqlite3

    以下我们将以一份NBA的历史赛程数据为例,来了解SQL的基本法则与应用方法。(数据来源:FiveThirtyEight)

    05. 查询

    与数据库进行通信的最基本形式是查询(query),即返回符合条件的数据子集,其基本关键字是SELECT,SELECT后面跟所选列的表头。前面提到过一个数据库里可能存在多个表,所以查询语句必须指定来源表,关键字是FROM。

    SELECT column1, column2, ... FROM table;

    注意SQL是要求句末有分号(;)的,这与Python的习惯大为不同,可能会唤起一度为C++支配的恐惧。

    NBA数据库里只含一张表,名为sheet,假设我们想要查询sheet表中的team_id列,那么对应的SQL是:

    SELECT team_id FROM nba_history;

    如果数据库非常庞大,那么即使哪怕仅仅查询某些列,也是不小的计算量,这里可以引入新的关键字LIMIT,之后接想要查询的行数。比如只想要前5行的team_id列,那么SQL为:

    SELECT team_id FROM nba_history LIMIT 5;

    下例将通过Python调用SQLite,查询elo_n和win_equiv两列的前5行:

    import sqlite3

    conn = sqlite3.connect('/mnt/vol0/Py_Intro/05_tuple_database/nbaallelo.db')

    cur = conn.cursor()

    # 代码补完

    query =

    #代码补完

    cur.execute(query)

    elos = cur.fetchall()

    conn.close()

    print(elos)

    可见,查询语句返回的是以元组(tuple)为元素的列表(list)。上例的输出即是5个(elo_n, win_equiv)组成的列表,应为:

    [(1293.2767, 40.29483), (1306.7233, 41.70517), (1309.6521, 42.012257), (1297.0712, 40.692783), (1279.6189, 38.864048)]

    06. SQLite with Python

    在04节最后的例子中,除了SQL语句,还有很多Python命令,这些是Python调用SQLite的语句。

    连接对象

    首先是建立与数据库的联系,sqlite3.connect()将返回Connection实例对象,然后存为conn变量,此时的conn对应的是整个数据库。

    import sqlite3

    conn = sqlite3.connect("/mnt/vol0/Py_Intro/05_tuple_database/nbaallelo.db")

    游标对象

    Connection对象的.cursor()可以创建游标对象(cursor object)。游标对象可以对数据库执行SQL语句并进行更灵活的数据操作。

    query是纯SQL语句,通过cur.execute()实际执行,此时数据库查询的结果仍在cur对象中。最后调用cur.fetchall()将查询结果全部返回,并存至变量elos,就是最终得到的元组列表。

    如果只想返回一条查询结果,可以使用cur.fetchone()。

    关于Python与SQLite3的联合应用,以后还会深入讲解,本篇仍将重点回归到SQL语句上。

    07. Where

    仅仅从数据库的某个表中查询某一列的前若干行,这样的操作局限性太大,很难满足应用需求。实际上我们感兴趣的数据子集并非总是按照顺序排列,而是符合某种限制条件。

    为了进一步缩减精确查询范围,可以使用关键字WHERE。比如我们想要查询NBA历史上,赛后elo值elo_n高于1850的强队ID,其SQL语句是:

    SELECT team_id, elo_n FROM sheet WHERE elo_n > 1850

    查询结果表明,历史上唯一一支elo值曾经突破1850的队伍是1996年总决赛时期的芝加哥公牛。

    下面请查询elo_n低于1100的弱队ID,及其对应比赛日期。sqlite3库以及连接对象、游标对象已经预定义,可以从定义SQL查询语句query开始。

    # 代码补完

    query =

    # 代码补完

    cur.execute(query)

    elo_1100 = cur.fetchall()

    conn.close()

    print(elo_1100)

    查询筛选结果显示,历史上一度衰到1100以下的弱旅,也只有1968年一支名为"Squires"的队伍。

    他们这么弱,我认为与名字起的不好是分不开的。"Squire"在英文中是“侍从”的意思,在《炉石传说》中,就有很多仆从名为"Squire",比如11圣盾小兵:

    交流群组:557373801

    想成为合作作者的朋友,欢迎与我联系。

    展开全文
  • Java的内存分配内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。 Java设计这四种引用的主要目的有两个: 可以让程序员...

    作者:CodeBear的园子 来源:www.cnblogs.com/CodeBear/p/12447554.html

    Java中的四种引用

    Java中有四种引用类型:强引用、软引用、弱引用、虚引用。

    Java为什么要设计这四种引用

    Java的内存分配和内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。

    Java设计这四种引用的主要目的有两个:

    1. 可以让程序员通过代码的方式来决定某个对象的生命周期;

    2. 有利用垃圾回收。

    强引用

    强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:

    Object o = new Object();

    这种就是强引用了,是不是在代码中随处可见,最亲切。

    只要某个对象有强引用与之关联,这个对象永远不会被回收,即使内存不足,JVM宁愿抛出OOM,也不会去回收。

    那么什么时候才可以被回收呢?当强引用和对象之间的关联被中断了,就可以被回收了。

    我们可以手动把关联给中断了,方法也特别简单:

    o = null;

    我们可以手动调用GC,看看如果强引用和对象之间的关联被中断了,资源会不会被回收,为了更方便、更清楚的观察到回收的情况,我们需要新写一个类,然后重写finalize方法,下面我们来进行这个实验:

    public class Student {    @Override
        protected void finalize() throws Throwable {
            System.out.println("Student 被回收了");
        }
    }
    
    public static void main(String[] args) {
        Student student = new Student();
        student = null;
        System.gc();
    }

    运行结果:

    Student 被回收了

    可以很清楚的看到资源被回收了。

    当然,在实际开发中,千万不要重写finalize方法

    在实际的开发中,看到有一些对象被手动赋值为NULL,很大可能就是为了“特意提醒”JVM这块资源可以进行垃圾回收了。点击这里获取一份 JVM 实战教程。

    软引用

    下面先来看看如何创建一个软引用:

     SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());

    软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了:

    SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());
    Student student = studentSoftReference.get();
    System.out.println(student);

    软引用有什么特点呢:

    当内存不足,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给干掉,也就是只有在内存不足,JVM才会回收该对象。

    还是一样的,必须做实验,才能加深印象:

    SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]);
    System.out.println(softReference.get());
    System.gc();
    System.out.println(softReference.get());
    byte[] bytes = new byte[1024 * 1024 * 10];
    System.out.println(softReference.get());

    我定义了一个软引用对象,里面包裹了byte[],byte[]占用了10M,然后又创建了10Mbyte[]。

    运行程序,需要带上一个参数:

    -Xmx20M

    代表最大堆内存是20M。

    运行结果:

    [B@11d7fff
    [B@11d7fff
    null

    可以很清楚的看到手动完成GC后,软引用对象包裹的byte[]还活的好好的,但是当我们创建了一个10M的byte[]后,最大堆内存不够了,所以把软引用对象包裹的byte[]给干掉了,如果不干掉,就会抛出OOM。

    软引用到底有什么用呢?比较适合用作缓存,当内存足够,可以正常的拿到缓存,当内存不够,就会先干掉缓存,不至于马上抛出OOM。说到缓存,大家可以关注微信公众号Java技术栈获取更多干货。

    弱引用

    弱引用的使用和软引用类似,只是关键字变成了WeakReference:

    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024\*1024\*10]);
    System.out.println(weakReference.get());

    弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:

    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
    System.out.println(weakReference.get());
    System.gc();
    System.out.println(weakReference.get());

    运行结果:

    [B@11d7fffnull

    可以很清楚的看到明明内存还很充足,但是触发了GC,资源还是被回收了。 弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。

    虚引用

    虚引用又被称为幻影引用,我们来看看它的使用:

    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());

    虚引用的使用和上面说的软引用、弱引用的区别还是挺大的,我们先不管ReferenceQueue 是个什么鬼,直接来运行:

    null

    竟然打印出了null,我们来看看get方法的源码:

    public T get() {
      return null;
    }

    这是几个意思,竟然直接返回了null。

    这就是虚引用特点之一了:无法通过虚引用来获取对一个对象的真实引用。

    那虚引用存在的意义是什么呢?这就要回到我们上面的代码了,我们把代码复制下,以免大家再次往上翻:

    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());

    创建虚引用对象,我们除了把包裹的对象传了进去,还传了一个ReferenceQueue,从名字就可以看出它是一个队列。

    虚引用的特点之二就是 虚引用必须与ReferenceQueue一起使用,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。

    我们来用代码实践下吧:

    ReferenceQueue queue = new ReferenceQueue();
    List<byte[]> bytes = new ArrayList<>();
    PhantomReference<Student> reference = new PhantomReference<Student>(new Student(),queue);
    new Thread(() -> {
        for (int i = 0; i < 100;i++ ) {
            bytes.add(new byte[1024 * 1024]);
        }
    }).start();
    
    new Thread(() -> {
        while (true) {
            Reference poll = queue.poll();
            if (poll != null) {
                System.out.println("虚引用被回收了:" + poll);
            }
        }
    }).start();
    Scanner scanner = new Scanner(System.in);
    scanner.hasNext();
    }

    运行结果:

    Student 被回收了
    虚引用被回收了:java.lang.ref.PhantomReference@1ade6f1

    我们简单的分析下代码: 第一个线程往集合里面塞数据,随着数据越来越多,肯定会发生GC。 第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。

    从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。

    虚引用有什么用呢?在NIO中,就运用了虚引用管理堆外内存。

    推荐去我的博客阅读更多:

    1.Java JVM、集合、多线程、新特性系列教程

    2.Spring MVC、Spring Boot、Spring Cloud 系列教程

    3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

    4.Java、后端、架构、阿里巴巴等大厂最新面试题

    觉得不错,别忘了点赞+转发哦!

    最后,关注下面的栈长的微信公众号:Java技术栈,回复:福利,可以免费获取一份我整理的 2020 最新 Java 面试题,真的非常全(含答案),无任何套路。

    展开全文
  • Java为什么要设计这四种引用Java的内存分配内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。Java设计这...

    f4d5c70a193a1d403c2000190a53ebc8.gif

    作者:CodeBear的园子

    来源:www.cnblogs.com/CodeBear/p/12447554.html

    Java中的四种引用

    Java中有四种引用类型:强引用、软引用、弱引用、虚引用。

    Java为什么要设计这四种引用

    Java的内存分配和内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。Java设计这四种引用的主要目的有两个:1.可以让程序员通过代码的方式来决定某个对象的生命周期;2.有利用垃圾回收。

    强引用

    强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:
    Object o = new Object();
    这种就是强引用了,是不是在代码中随处可见,最亲切。 只要某个对象有强引用与之关联,这个对象永远不会被回收,即使内存不足,JVM宁愿抛出OOM,也不会去回收。那么什么时候才可以被回收呢?当强引用和对象之间的关联被中断了,就可以被回收了。我们可以手动把关联给中断了,方法也特别简单:
    o = null;
    我们可以手动调用GC,看看如果强引用和对象之间的关联被中断了,资源会不会被回收,为了更方便、更清楚的观察到回收的情况,我们需要新写一个类,然后重写finalize方法,下面我们来进行这个实验:
    public class Student {    @Override
        protected void finalize() throws Throwable {
            System.out.println("Student 被回收了");
        }
    }

    public static void main(String[] args) {
        Student student = new Student();
        student = null;
        System.gc();
    }
    运行结果:
    Student 被回收了
    可以很清楚的看到资源被回收了。当然,在实际开发中,千万不要重写finalize方法在实际的开发中,看到有一些对象被手动赋值为NULL,很大可能就是为了“特意提醒”JVM这块资源可以进行垃圾回收了。点击这里获取一份 JVM 实战教程。

    软引用

    下面先来看看如何创建一个软引用:
     SoftReferencestudentSoftReference=new SoftReference(new Student());
    软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了:
    SoftReferencestudentSoftReference=new SoftReference(new Student());
    Student student = studentSoftReference.get();
    System.out.println(student);
    软引用有什么特点呢: 当内存不足,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给干掉,也就是只有在内存不足,JVM才会回收该对象。

    还是一样的,必须做实验,才能加深印象:

    SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]);
    System.out.println(softReference.get());
    System.gc();
    System.out.println(softReference.get());        
    byte[] bytes = new byte[1024 * 1024 * 10];
    System.out.println(softReference.get());
    我定义了一个软引用对象,里面包裹了byte[],byte[]占用了10M,然后又创建了10Mbyte[]。运行程序,需要带上一个参数:
    -Xmx20M
    代表最大堆内存是20M。运行结果:
    [B@11d7fff
    [B@11d7fff
    null
    可以很清楚的看到手动完成GC后,软引用对象包裹的byte[]还活的好好的,但是当我们创建了一个10M的byte[]后,最大堆内存不够了,所以把软引用对象包裹的byte[]给干掉了,如果不干掉,就会抛出OOM。软引用到底有什么用呢?比较适合用作缓存,当内存足够,可以正常的拿到缓存,当内存不够,就会先干掉缓存,不至于马上抛出OOM。说到缓存,大家可以关注微信公众号Java技术栈获取更多干货。

    弱引用

    弱引用的使用和软引用类似,只是关键字变成了WeakReference:
    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024\*1024\*10]);
    System.out.println(weakReference.get());
    弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:
    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
    System.out.println(weakReference.get());
    System.gc();
    System.out.println(weakReference.get());
    运行结果:
    [B@11d7fffnull
    可以很清楚的看到明明内存还很充足,但是触发了GC,资源还是被回收了。 
    弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。

    虚引用

    虚引用又被称为幻影引用,我们来看看它的使用:
    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());
    虚引用的使用和上面说的软引用、弱引用的区别还是挺大的,我们先不管ReferenceQueue 是个什么鬼,直接来运行:
    null
    竟然打印出了null,我们来看看get方法的源码:
    public T get() {        
      return null;
    }
    这是几个意思,竟然直接返回了null。这就是虚引用特点之一了:无法通过虚引用来获取对一个对象的真实引用。那虚引用存在的意义是什么呢?这就要回到我们上面的代码了,我们把代码复制下,以免大家再次往上翻:
    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());
    创建虚引用对象,我们除了把包裹的对象传了进去,还传了一个ReferenceQueue,从名字就可以看出它是一个队列。虚引用的特点之二就是 虚引用必须与ReferenceQueue一起使用,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。我们来用代码实践下吧:
    ReferenceQueue queue = new ReferenceQueue();
    List bytes = new ArrayList<>();
    PhantomReference reference = new PhantomReference(new Student(),queue);new Thread(() -> {for (int i = 0; i 100;i++ ) {
            bytes.add(new byte[1024 * 1024]);
        }
    }).start();new Thread(() -> {while (true) {
            Reference poll = queue.poll();if (poll != null) {
                System.out.println("虚引用被回收了:" + poll);
            }
        }
    }).start();
    Scanner scanner = new Scanner(System.in);
    scanner.hasNext();
    }
    运行结果:
    Student 被回收了
    虚引用被回收了:java.lang.ref.PhantomReference@1ade6f1

    我们简单的分析下代码: 

    第一个线程往集合里面塞数据,随着数据越来越多,肯定会发生GC。 
    第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。

    从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。虚引用有什么用呢?在NIO中,就运用了虚引用管理堆外内存。

    8f0f6e6d765c912394428529f3fa86fa.png

    展开全文
  • Java为什么要设计这四种引用Java的内存分配内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。Java设计这四种引用的主要...

    e5d6fcdf6bf857fb4165d1b585ddd3d5.png

    Java中的四种引用

    Java中有四种引用类型:强引用、软引用、弱引用、虚引用。

    Java为什么要设计这四种引用

    Java的内存分配和内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。

    Java设计这四种引用的主要目的有两个:

    1. 可以让程序员通过代码的方式来决定某个对象的生命周期;
    2. 有利用垃圾回收。

    强引用

    强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:

    Object o = new Object();

    这种就是强引用了,是不是在代码中随处可见,最亲切。

    只要某个对象有强引用与之关联,这个对象永远不会被回收,即使内存不足,JVM宁愿抛出OOM,也不会去回收。

    那么什么时候才可以被回收呢?当强引用和对象之间的关联被中断了,就可以被回收了。

    我们可以手动把关联给中断了,方法也特别简单:

    o = null;

    我们可以手动调用GC,看看如果强引用和对象之间的关联被中断了,资源会不会被回收,为了更方便、更清楚的观察到回收的情况,我们需要新写一个类,然后重写finalize方法,下面我们来进行这个实验:

    public class Student {    @Override
        protected void finalize() throws Throwable {
            System.out.println("Student 被回收了");
        }
    }
    
    public static void main(String[] args) {
        Student student = new Student();
        student = null;
        System.gc();
    }

    运行结果:

    Student 被回收了

    可以很清楚的看到资源被回收了。

    当然,在实际开发中,千万不要重写finalize方法

    在实际的开发中,看到有一些对象被手动赋值为NULL,很大可能就是为了“特意提醒”JVM这块资源可以进行垃圾回收了。点击这里获取一份 JVM 实战教程。

    软引用

    下面先来看看如何创建一个软引用:

     SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());

    软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了:

    SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());
    Student student = studentSoftReference.get();
    System.out.println(student);

    软引用有什么特点呢:

    当内存不足,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用的包裹的对象给干掉,也就是只有在内存不足,JVM才会回收该对象。

    还是一样的,必须做实验,才能加深印象:

    SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]);
    System.out.println(softReference.get());
    System.gc();
    System.out.println(softReference.get());        
    byte[] bytes = new byte[1024 * 1024 * 10];
    System.out.println(softReference.get());

    我定义了一个软引用对象,里面包裹了byte[],byte[]占用了10M,然后又创建了10Mbyte[]。

    运行程序,需要带上一个参数:

    -Xmx20M

    代表最大堆内存是20M。

    运行结果:

    [B@11d7fff
    [B@11d7fff
    null

    可以很清楚的看到手动完成GC后,软引用对象包裹的byte[]还活的好好的,但是当我们创建了一个10M的byte[]后,最大堆内存不够了,所以把软引用对象包裹的byte[]给干掉了,如果不干掉,就会抛出OOM。

    软引用到底有什么用呢?比较适合用作缓存,当内存足够,可以正常的拿到缓存,当内存不够,就会先干掉缓存,不至于马上抛出OOM。说到缓存,大家可以关注微信公众号Java技术栈获取更多干货。

    弱引用

    弱引用的使用和软引用类似,只是关键字变成了WeakReference:

    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024*1024*10]);
    System.out.println(weakReference.get());

    弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:

    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
    System.out.println(weakReference.get());
    System.gc();
    System.out.println(weakReference.get());

    运行结果:

    [B@11d7fffnull

    可以很清楚的看到明明内存还很充足,但是触发了GC,资源还是被回收了。
    弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。

    虚引用

    虚引用又被称为幻影引用,我们来看看它的使用:

    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());

    虚引用的使用和上面说的软引用、弱引用的区别还是挺大的,我们先不管ReferenceQueue 是个什么鬼,直接来运行:

    null

    竟然打印出了null,我们来看看get方法的源码:

    public T get() {        
      return null;
    }

    这是几个意思,竟然直接返回了null。

    这就是虚引用特点之一了:无法通过虚引用来获取对一个对象的真实引用。

    那虚引用存在的意义是什么呢?这就要回到我们上面的代码了,我们把代码复制下,以免大家再次往上翻:

    ReferenceQueue queue = new ReferenceQueue();
    PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
    System.out.println(reference.get());

    创建虚引用对象,我们除了把包裹的对象传了进去,还传了一个ReferenceQueue,从名字就可以看出它是一个队列。

    虚引用的特点之二就是 虚引用必须与ReferenceQueue一起使用,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。

    我们来用代码实践下吧:

    ReferenceQueue queue = new ReferenceQueue();
    List<byte[]> bytes = new ArrayList<>();
    PhantomReference<Student> reference = new PhantomReference<Student>(new Student(),queue);
    new Thread(() -> {
        for (int i = 0; i < 100;i++ ) {
            bytes.add(new byte[1024 * 1024]);
        }
    }).start();
    
    new Thread(() -> {
        while (true) {
            Reference poll = queue.poll();
            if (poll != null) {
                System.out.println("虚引用被回收了:" + poll);
            }
        }
    }).start();
    Scanner scanner = new Scanner(System.in);
    scanner.hasNext();
    } 

    运行结果:

    Student 被回收了
    虚引用被回收了:java.lang.ref.PhantomReference@1ade6f1

    我们简单的分析下代码:
    第一个线程往集合里面塞数据,随着数据越来越多,肯定会发生GC。
    第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。

    从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。

    虚引用有什么用呢?在NIO中,就运用了虚引用管理堆外内存。


    原作者:CodeBear
    原文链接:强软弱虚引用,只有体会过了,才能记住 - CodeBear - 博客园
    原出处:博客园
    侵删

    f8adc45d4e91aa361b13f8e8a2cda64b.gif
    展开全文
  • Java为什么要设计这四种引用Java的内存分配内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。Java设计这...
  • sigma模型由两个阿贝尔规范玻色子和一个真实的,不带电荷的标量场组成,在五个维度上与重力耦合。 标量势是标量场的简单指数函数。 解决经典运动方程式所产生的背景度量至少在径向方向上渐近大时表现出超标度违规。...
  • 点击蓝字关注我们前言每种编程语言都有...但其实操作时候的标识符并不是真正的对象,而是对象的一个引用(reference)。通过将这个叫“引用”的标识符指向某个对象,之后便可以使用这个引用来实现操作对象了。在 JDK...
  • 强类型和弱类型语言

    2019-03-22 18:10:45
    答:语言类型的强弱是种语言针对类型检查的严格程度而言的,它指的是变量在使用的时候是否需要指定这变量的类型,并且在程序的运行过程变量是否只能存储这类型的数据。 问:根据语言的强弱可分为几类...
  • 如何构造第一个弱分类器(树桩) 先给每个样本一个初始的权重=1/样本总数 确定选用哪个特征:Gini系数 分别计算左右两边的纯度:1-(预测正确的比例)2-(预测错误的比例)2 然后加权平均 例如Chest Pa
  • 鸡小富翁

    2019-10-06 11:50:56
    使用类可以使得整个代码的结构清晰,哪一部分的功能调用哪一个类,这样在出现问题的时候,能够精准快速地找到问题改正问题。当然不仅如此,还有要添加新功能,还是修改一些方法,直接在类中修...
  • 一、概念 ...因此,当认证完成后。就需要替换一个对用户透明的凭证。这个凭证就是SessionID。...会话会保存用户的状态相关信息。...为了告诉服务器应该使用哪一个Session,浏览器需要把当前用户持有的Ses
  • 1、Java几种引用?它们的含义区别是什么? 1)强引用(StrongReference) 强引用是使用最普遍的引用,如果一个对象具有强引用,那么垃圾回收器绝对不会回收它,当内存控件不足时,java虚拟机宁愿抛出...
  • 语言节奏,快节奏是指音量大、声音高、语速快,慢节奏是指音量小、声音低、语速慢,社交能力强是指见面后对你非常热情,社交能力是指对你不理不睬、半天不说句话。   要想了解客户的性格特点,一定要经过三...
  • 分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍来!请点击http://www.captainbed.net Spring支持编程式事务管理声明式事务管理。许多Spring框架的用户选择声明式事务...
  • 让我们先看一组新产品开发成功率的数据: “每七个观念,有一个能获得成功”“每四个开发项目,只有一个成为商业上的成功者”“即使在完成阶段(完成了所有测试,审查计划每一步之后),每三个项目还有一个在...
  • JavaScript是类型客户端的编程语言,新手在系统学习JavaScript之前需要了解Javascript基础语法规则,也称语言规则。今天西安鸥鹏教育主要为大家介绍关于JavaScript的一些小常识!零基础学JavaScript要掌握的...
  • iOSstrong&weak_block&_weak的作用比较

    千次阅读 2015-05-10 19:28:48
    iOS 开发经常会用strongweak来修饰一些属性,这两的区别又在。。 就像图片的这样,AB都要引用C对象,可是AC之间是实线(强引用),BC之间是虚线(引用)。不论B是否还在引用C(即不论虚线是否存在...
  • 我一直对这词所代表的学术概念嗤之以鼻,不为别的,就因为这些概念严重的欺负了我对概念性知识的超理解能力。正是如此,让我一直对明确其概念这行为抱有深深的芥蒂。 不过,能跟自己过不去呢?于是,在不断...
  • 狭义的AI(AI): 这种AI只专注于一种狭义的任务。现在我们的身边已经处处都是AI了。它已经在国际象棋,电视竞赛节目《危险边缘》,还有最近的围棋比赛击败...AI有一个狭隘的范围:它不能超越最先为其设置的...
  • Java 的对象是位于 heap 的,heap 对象有强可及对象、软可及对象、可及对象、虚可及对象不可到达对象。应用的强弱顺序是强、软、虚。对于对象是属于种可及的对象,由他的最强的引用决定。这4种级别...
  • 耦合内聚

    2014-04-07 18:31:55
    耦合是软件结构各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 2.内聚分为几类?耦合分为几类? 内聚有如下的种类,它们之间的内聚度...
  • i510300hr54600h的区别 哪个好

    万次阅读 2020-08-22 20:37:24
    i5 10300这cpu,大约相当于台式机的R5 2500u或者是i5 7500,性能比i5 7500还要一点。由于笔记本的低压,散热等关系,实际表现上是要于台式机的。频率(基频2.5GHz、加速4.3GHz)本身分别高了100、200MHz。...
  • 逻辑内聚:指模块内执行若干个逻辑上相似的功能,通过参数确定该模块完成哪一个功能。 时间内聚:把需要同时执行的动作组合在一起形成的模块。 过程内聚:指一个模块完成多个任务,这些任务必须按指定的过程执行。
  • 今日头条轮游

    2017-12-15 14:05:13
    人生最尴尬的次面试QAQ ...4.Java的四种引用,软引用和弱引用分别在什么情况下使用; 5.缓存机制,Lru Cache的替换算法,在不使用计数器的情况下如何使用Lru算法; 6.虚拟内存,逻辑地址与物

空空如也

空空如也

1 2 3 4 5 6
收藏数 103
精华内容 41
关键字:

中弱和弱哪一个弱