从局部变量说起,关于一个莫得名堂的引用和一个坑!

你好呀,我是歪歪。

今天,我将向大家展示一些有趣的基础知识。

[En]

Today, I will show you some interesting basic knowledge.

它有多基本?我先给你一个代码:

[En]

How basic is it? I’ll give you a code first:

请问,上面代码中,位于 method 方法中的 object 对象,在方法执行完成之后,是否可以被垃圾回收?

你还在想什么呢?它必须是可能的,因为它是一个局部变量,其作用域是方法之间的。

[En]

What else are you thinking about? it has to be possible, because it’s a local variable, and its scope is between methods.

JVM 在执行方法时,会给方法创建栈帧,然后入栈,方法执行完毕之后出栈。

一旦方法栈帧出栈,栈帧里的局部变量,也就相当于不存在了,因为没有任何一个变量指向 Java 堆内存。

换句话说:它结束了,它是遥不可及的。

[En]

In other words: it’s over, it’s unreachable.

这是一个基本的知识点,我在骗你吗?

[En]

This is a basic knowledge point, am I lying to you?

那么我现在换个写法:

你说在 method 方法执行完成之后,executorService 对象是否可以被垃圾回收呢?

别想复杂了,这个东西和刚刚的 Object 一样,同样是个局部变量,肯定可以被回收的。

但接下来我要开始制造麻烦了:

[En]

But then I’m going to start making trouble:

我请求线程池执行一个任务,这相当于激活线程池,但线程池仍然是一个局部变量。

[En]

I asked the thread pool to perform a task, which is equivalent to activating the thread pool, but the thread pool is still a local variable.

那么问题就来了:在上面的示例代码中,executorService 对象是否可以被垃圾回收呢?

在这一点上,你需要扣紧你的头骨,考虑一下。

[En]

At this point, you need to buckle your skull and think about it.

不要屈服,让我们从结论开始:它不能被回收利用。

[En]

Don’t buckle, let’s start with the conclusion: it can’t be recycled.

然后我要提出的问题是:这也是一个局部变量,为什么它不能被循环使用?

[En]

And then the question that I’m going to raise is: this is also a local variable, why can’t it be recycled?

为什么

您知道线程池中有活动的线程,因此直觉上它不应该被回收。

[En]

You know that there are active threads in the thread pool, so intuitively it should not be recycled.

但是证据,你必须拿出完整的证据链。

[En]

But the evidence, you have to come up with a complete chain of evidence.

好的,让我问你,一个物体被判定为垃圾并可以回收的依据是什么?

[En]

OK, let me ask you, what is the basis on which an object is judged to be garbage and can be recycled?

这时,你脑海中立刻浮现出七个字–可达性分析算法。一旦你滑动,你会想到一张这样的图片:

[En]

At this time, the seven words “reachability analysis algorithm” immediately pop up in your mind. Once you swipe, you will think of a picture like this:

必须做到和看到 KFC 的时候,立马就想到 v 我 50 一样自然。

这个算法的基本思路就是通过一系列称为”GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为”引用链”(Reference Chain),如果某个对象到 GC Roots 间没有任何引用链相连,或者用图论的话来说就是从 GC Roots 到这个对象不可达时,则证明此对象是不可能再被使用的。

所以如果要推理 executorService 是不会被回收的,那么就得推理出 GC Root 到 executorService 对象是可达的。

那么哪些对象是可以作为 GC Root 呢?

老八股文了,不过多说。

只看本文关心的部分:live thread,是可以作为 GC Root 的。

所以,由于我在线程池里面运行了一个线程,即使它把任务运行完成了,它也只是 wait 在这里,还是一个 live 线程:

因此,我们只要能找到这样的一个链路就可以证明 executorService 这个局部变量不会被回收:

live thread(GC Root) -> executorService

一个 live thread 对应到代码,一个调用了 start 方法的 Thread,这个 Thread 里面是一个实现了 Runnable 接口的对象。

这个实现了 Runnable 接口的对象对应到线程池里面的代码就是这个玩意:

java.util.concurrent.ThreadPoolExecutor.Worker

然后我们可以使上面的链接更具体一些:

[En]

Then we can make the above link a little more specific:

Worker(live thread) -> ThreadPoolExecutor(executorService)

也就是找 Worker 类到 ThreadPoolExecutor 类的引用关系。

有的同学立马就站起来抢答了:hi,就这?我以为多狠呢?这个我熟悉啊,不就是它吗?

你看,ThreadPoolExecutor 类里面有个叫做 workers 的成员变量。

我只是笑了笑:是的,然后呢?

[En]

I just smiled: yes, and then what?

抢答的同学立马就回答到:然后就证明 ThreadPoolExecutor 类是持有 workers 的引用啊?

我接着问:没什么问题,然后呢?

[En]

I went on to ask: nothing wrong, and then what?

这位同学自言自语道:“难道这一切还没有结束吗?”

[En]

The classmate muttered to himself, “then isn’t it over?”

是的,一切都结束了。今天的采访到此结束。回去等待通知。

[En]

Yes, it’s over. Today’s interview is over. Go back and wait for notice.

我的问题是:找 Worker 类到 ThreadPoolExecutor 类的引用关系。

你这弄反了啊。

有的同学里面又要说了:这个问题,直接看 Worker 类不就行了,看看里面有没有一个 ThreadPoolExecutor 对象的成员变量。

不好意思,这个真没有:

到底怎么回事?它能回收利用吗?

[En]

What’s going on? Can it be recycled?

但是如果 ThreadPoolExecutor 对象被回收了,Worker 类还存在,那岂不是很奇怪,线程池没了,线程还在?

没有皮,头发就不会附着,奇怪啊,奇怪。

[En]

Without the skin, the hair will not be attached, strange ah, strange.

看着这位同学陷入了一种自我怀疑的状态,我刚刚开始了一项“不思考”的技能:坐下!听我说!

[En]

Watching this classmate fall into a state of self-doubt, I just started a “no-think” skill: sit down! Listen to me!

开始上课

接下来,先忘记线程池,我给大家搞个简单的 Demo,回归本源,分析起来就简单一点了:

public&#xA0;class&#xA0;Outer&#xA0;{<br><br>&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;int&#xA0;num&#xA0;=&#xA0;0;<br><br>&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;int&#xA0;<span class="hljs-function"><span class="hljs-title">getNum</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="hljs-built_in">return</span>&#xA0;num;<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;setNum(int&#xA0;num)&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;this.num&#xA0;=&#xA0;num;<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;//&#x5185;&#x90E8;&#x7C7B;<br>&#xA0;&#xA0;&#xA0;&#xA0;class&#xA0;Inner&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;private&#xA0;void&#xA0;<span class="hljs-function"><span class="hljs-title">callOuterMethod</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;setNum(18);<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br>}

Inner 类是 Outer 类的一个内部类,所以它可以直接访问 Outer 类的变量和方法。

这个写法大家应该没啥异议,日常的开发中有时也会写内部类,我们稍微深入的想一下:为什么 Inner 类可以直接用父类的东西呢?

因为非静态内部类持有外部类的引用。

这句话很重要,可以说就是因为这句话我才写了这篇文章。

[En]

This sentence is very important, it can be said that it is because of this sentence that I wrote this article.

接下来,让我来证明这一点。

[En]

Next, let me prove this point.

怎么证明呢?

很简单,javac 编译一波,答案都藏在 Class 里面。

可以看到, Outer.java 反编译之后出来了两个 Class 文件:

它们分别是这样的:

在 Outer&Inner.class 文件中,我们可以看到 Outer 在构造函数里面被传递了进来,这就是为什么我们说:为非静态内部类持有外部类的引用。

好了,理论知识和验证完成后,让我们回到线程池:

[En]

Well, with the theoretical knowledge and verification complete, let’s go back to the thread pool:

Worker 类是 ThreadPoolExecutor 类的内部类,所以它持有 ThreadPoolExecutor 类的引用。

因此这个链路是成立的,executorService 对象不会被回收。

Worker(live thread) -> ThreadPoolExecutor(executorService)

如果你不相信我,我再给你看一样东西。

[En]

If you don’t believe me, I’ll show you one more thing.

我的 IDEA 里面有一个叫做 Profile 的插件,程序运行起来之后,在这里面可以对内存进行分析:

我根据 Class 排序,很容易就能找到内存中存活的 ThreadPoolExecutor 对象:

点击查看,这不是我定义的核心线程数吗,最大线程数是3,并且线程池中只有一个线程被激活?

[En]

Click in and see, isn’t this the number of core threads I defined, the maximum number of threads is 3, and only one thread is activated in the thread pool?

从 GC Root 也能直接找到我们需要验证的链路:

所以,让我们回到原来的问题上:

[En]

So, let’s go back to the original question:

在上面的示例代码中,executorService 对象是否可以被垃圾回收呢?

答案是不可以,因为线程池里面有活跃线程,活跃线程是 GC Root。这个活跃线程,其实就是 Woker 对象,它是 ThreadPoolExecutor 类的一个内部类,持有外部类 ThreadPoolExecutor 的引用。所以,executorService 对象是”可达”,它不可以被回收。

道理,就这么一个道理。

然后是问题:应该如何回收这个本地线程池?

[En]

Then comes the question: what should be done to recycle this local thread pool?

调用 shutdown 方法,干掉 live 线程,也就是干掉 GC Root,整个的就是个不可达。

垃圾回收线程一看:嚯~好家伙,过来吧,您呢。

延伸一下

让我们来看看我之前提到的结论:

[En]

Let’s take a look at the conclusion I mentioned earlier:

非静态内部类持有外部类的引用。

强调了一个”非静态”,如果是静态内部类呢?

把 Inner 标记为 static 之后, Outer 类的 setNum 方法直接就不让你用了。

如果要使用的话,得把 Inner 的代码改成这样:

或者改成这样:

也就是说,它必须显示以容纳外部和内部对象,所以大胆猜测为什么?

[En]

That is, it must be displayed to hold an external and internal object, so take a bold guess why?

有没有可能静态内部类不包含对外部类的引用,并且它们之间根本没有关系?

[En]

Is it possible that static inner classes do not hold references to external classes, and there is no relationship between them at all?

答案我们还是可以从 class 文件中找到:

当我们给 inner 类加上 static 之后,它就不在持有外部内的引用了。

在这一点上,我们可以得出另一个结论:

[En]

At this point, we can come to another conclusion:

静态内部类不持有外部类的引用。

然后,文本的第一个扩展点就出来了。

[En]

Then the first extension point of the text comes out.

也就是《Effective Java(第三版)》中的第 24 条:

比如,还是线程池的源码,里面的拒绝策略也是内部类,它就是 static 修饰的:

为什么不和 woker 类一样,弄成非静态呢?

这是为了告诉我:当我们使用内部类时,我们应该尝试使用静态内部类,这样就不会莫名其妙地持有对外部类的引用,而不必向上。

[En]

This is to tell me: when we are using inner classes, we should try to use static inner classes so as not to inexplicably hold a reference to an external class without having to go up.

事实上,如果你不需要,那也没什么大不了的。

[En]

Actually, it’s not a big deal if you don’t need it.

真正可怕的是内存泄漏。

[En]

What’s really scary is the memory leak.

例如,互联网上的这个测试用例:

[En]

For example, this test case on the Internet:

Inner 类不是静态内部类,所以它持有外部类的引用。但是,在 Inner 类里面根本就不需要使用到外部类的变量或者方法,比如这里的 data。

你想象一下,如果 data 变量是个很大的值,那么在构建内部类的时候,由于引用存在,不就不小心额外占用了一部分本来应该被释放的内存吗。

所以这个测试用例跑起来之后,很快就发生了 OOM:

怎么断开这个”没得名堂”的引用呢?

前面提到了使用静态内部类的解决方案:

[En]

The solution was mentioned earlier, using static inner classes:

只是在 Inner 类上加上 static 关键字,不需要其他任何变动,问题就得到了解决。

但是这个 static 也不是无脑直接加的,在这里可以加的原因是因为 Inner 类完全没有用到 Outer 类的任何变量和属性。

所以,再次重申《Effective Java(第三版)》中的第 24 条:静态内部类优于非静态内部类。

你看,他用的是”优于”,意思是优先考虑,而不是强行怼。

再延伸一下

关于”静态内部类”这个叫法,我记得我从第一次接触到的时候就是这样叫它的,或者说大家都是这样叫的。

然后我写文章的时候,一直在 JLS 里面找 “Static Inner Class” 这样的关键词,但是确实是没找到。

在 Inner Class 这一部分,Static Inner Class 这三个单词并没有连续的出现在一起过:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3

直到我找到了这个地方:

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

在 Java 官方教程里面,关于内部类这部分,有这样一个小贴士:

嵌套类分为两类:非静态和静态。非静态的嵌套类被称为内部类(inner classes)。被声明为静态的嵌套类被称为静态嵌套类(static nested classes)。

看到这句话的时候,我一下就反应过来了。大家习以为常的 Static Inner Class,其实是没有这样的叫法的。

nested,嵌套。

我认为这里有一个翻译问题。

[En]

I think there is a translation problem here.

首先,在一个类中定义另一个类的操作在官方文档中称为嵌套类。

[En]

First of all, the operation of defining another class in one class is called a nested class in the official documentation.

没有加 static 的嵌套类被称为内部类,从使用上来说,要实例化内部类,必须首先实例化外部类。

代码得这样写:

//先搞出内部类
OuterClass outerObject = new OuterClass();
//才能搞出内部类
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

所以这个 Inner 就很传神,打个比分,它就像是我的肾,是我身体的一部分,它 Inner 我。

加了 static 的嵌套类被称为静态嵌套类,和 Inner 完全就不沾边。

这个 nested 也就很传神,它的意思就是我本来是可以独立存在的,不用依附于某个类,我依附你也只是借个壳而已,我嵌套一下。

打个比分,它就像是我的手机,它随时都在我的身上,但是它并不 Inner 我,它也可以独立于我存在。

所以,一个 Inner ,一个 nested。一个肾,一个手机,它能一样吗?

当然,如果你不得不用你的肾脏换一部手机。

[En]

Of course, if you have to trade your kidney for a cell phone.

这种翻译问题也让我想起了在知乎上看到的类似问题:

[En]

This kind of translation problem also reminds me of a similar problem I saw in Zhihu:

为什么很多编程语言要把 0 设置为第一个元素下标索引,而不是直观的 1 ?

以下是一个简明而富有启发性的答案:

[En]

Here is a concise and enlightening answer:

还可以延伸一下

接下来,让我们把目光放到《Java并发编程实战》这本书上来。

还有一段与这篇文章相关的代码,乍一看让无数人摸不着头脑。

[En]

There is also a piece of code related to this article, which is puzzled by countless people at first glance.

书上说下这段代码是有问题的,会导致 this 引用逸出。

第一次看的时候,我迷惑不解,好几次都看不懂:

[En]

When I saw it for the first time, I was so confused that I didn’t understand it several times:

然后就跳过了…

直到很久以后,我才明白作者想说的是什么。

[En]

It was not until a long time later that I understood what the author was trying to say.

现在我给你们拿一张这段代码的磁盘,让你们明白。

[En]

Now I will take you a disk of this code, make it clear.

我会先完成书中的代码。所有代码都是这样的:

[En]

I’ll complete the code in the book first. all the code goes like this:

public&#xA0;class&#xA0;ThisEscape&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;ThisEscape(EventSource&#xA0;<span class="hljs-built_in">source</span>)&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;source.registerListener(new&#xA0;<span class="hljs-function"><span class="hljs-title">EventListener</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;onEvent(Event&#xA0;e)&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;doSomething(e);<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;});<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;void&#xA0;doSomething(Event&#xA0;e)&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br><br>&#xA0;&#xA0;&#xA0;&#xA0;interface&#xA0;EventSource&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;void&#xA0;registerListener(EventListener&#xA0;e);<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;interface&#xA0;EventListener&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;void&#xA0;onEvent(Event&#xA0;e);<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;interface&#xA0;Event&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br>}

代码要是你一眼看不明白,没关系,主要是关注 EventListener 这个玩意,你看它其实是一个接口对不对。

好的,我给你改一下,用你看起来更眼熟的方式写:

[En]

Okay, I’ll change it for you and write it in a way that you look a little more familiar:

Runnable 和 EventListener 都是接口,所以这样的写法和书中的示例代码没有本质上的区别。

但这只会让人看起来很眼熟。

[En]

But it just makes people look familiar.

然后其实这个 EventSource 接口也并不影响我最后要给你演示的东西,所以我把它也干掉,代码就可以简化到这个样子:

public&#xA0;class&#xA0;ThisEscape&#xA0;{<br><br>&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;<span class="hljs-function"><span class="hljs-title">ThisEscape</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;new&#xA0;<span class="hljs-function"><span class="hljs-title">Runnable</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;@Override<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;public&#xA0;void&#xA0;<span class="hljs-function"><span class="hljs-title">run</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;doSomething();<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;};<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br><br>&#xA0;&#xA0;&#xA0;&#xA0;void&#xA0;<span class="hljs-function"><span class="hljs-title">doSomething</span></span>()&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;}<br>}

在 ThisEscape 类的无参构造里面,有一个 Runnable 接口的实现,这种写法叫做匿名内部类。

看到内部类,再看到书中提到的 this 逸出,再想起前面刚刚才说的非静态内部类持有外部类的引用你是不是想起了什么?

验证一下你的想法,我通过 javac 编译这个类,然后查看它的 class 文件如下:

我们果然看到了 this 关键字,所以 “this 逸出”中的 this 指的就是书中 ThisEscape 这个类。

逃亡,会带来什么问题?

[En]

Escape, what problems does it bring?

来看看这个代码:

由于 ThisEscape 对象在构造方法还未执行完成时,就通过匿名内部类”逸”了出去,这样外部在使用的时候,比如 doSomething 方法就拿到可能是一个还未完全完成初始化的对象,就会导致问题。

我觉得书中的这个案例,读者只要是抓住了”内部类”和”this是谁”这两个关键点,就会比较容易吸收。

针对”this逸出”的问题,书中也给出了对应的解决方案:

作为一个指南,我不会详细说明。我有兴趣亲自体验一下。

[En]

As a guide, I won’t go into details. I’m interested in going through it myself.

最后,文章首发在公众号【why技术】,欢迎大家关注。

Original: https://www.cnblogs.com/thisiswhy/p/16798811.html
Author: why技术
Title: 从局部变量说起,关于一个莫得名堂的引用和一个坑!



相关阅读

Title: findfont: Font family [‘Times New Roman‘] not found. Falling back to DejaVu Sans.

问题背景:

远程使用服务器绘图时,设置font_dict中字体格式为’Times New Roman’,如下:

font_dict=dict(fontsize=16,
              color='black',
              family='Times New Roman',
            #   weight='light',
              style='italic',
              )

在绘图过程中报告以下错误:

[En]

The following error is reported during the drawing process:

findfont: Font family ['Times New Roman'] not found. Falling back to DejaVu Sans.

错误原因:

服务器上缺少Times New Roman对应字体文件。

解决方案:

在服务器上安装 Times New Roman 字体文件。

step1:获取Times New Roman字体文件

方法1(推荐):

从win10系统上寻找,寻找路径是:’C:\Windows\Fonts’,搜索”Times New Roman”,搜索结果如下。复制该文件到桌面,可以得到四个文件:times.tiff, timesbd.tiff, timesbi.tiff, timesi.tiff.

从局部变量说起,关于一个莫得名堂的引用和一个坑!

方法2:

从网络上下载,下载网址是http://www.xiazaiziti.com/?s=times+new+roman.

step2:复制”time new roman”文件到服务器上

把四个”time new roman”文件复制到服务器上 matplotlib库对应的 fonts/ttf 文件夹下,我的路径是”/home/wzg/anaconda3/envs/LSTM-C3D-GAN/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf”,该路径可以通过以下代码查看:

python
>>> import matplotlib
>>> print(matplotlib.matplotlib_fname())

step3:删除之前的字体缓存

方法1:

手工找到”home/wzg/.cache/matplotlib”目录并删除该目录,地址中的wzg是用户名,根据实际情况自行更改。如果找不到cache文件夹,是因为其为隐藏文件夹,可ctrl+h将其显示。

方法2:

在终端窗口输入以下指令寻找”home/wzg/.cache/matplotlib”目录,

python
>>> import matplotlib
>>> matplotlib.get_cachedir()

找到隐藏的文件夹,如下图所示

[En]

Find the hidden folder, as shown in the following figure

从局部变量说起,关于一个莫得名堂的引用和一个坑!

然后删除该文件夹。

参考:Linux下的python修改画图的字体_刘西北的博客-CSDN博客_linux python 字体

使用matplotlib时缺失字体,findfont: Font family [‘Times New Roman’] not found. Falling back to DejaVu Sans._ixobgenw的博客-CSDN博客

1238: UserWarning: findfont: Font family [‘sans-serif’] not found. Falling back to DejaVu Sans. – 灰信网(软件开发博客聚合)

Original: https://blog.csdn.net/Strive_For_Future/article/details/122881061
Author: wzg2016
Title: findfont: Font family [‘Times New Roman‘] not found. Falling back to DejaVu Sans.

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/363335/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 关于matplotlib下载和使用的tips

    抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。 Original: https:…

    Python 2023年1月14日
    033
  • yolov5+Vue+Flask部署流程与报错解决

    1、使用Vue框架的程序首先需要安装node.js,这是一个类似js的运行环境的东西,安装包地址为https://nodejs.org/zh-cn/,下载后直接运行安装,期间会运行…

    Python 2023年1月5日
    035
  • [同人] 我的莱昂

    “我的天啊,乔治”金发男孩哭丧着脸,一边揉着肩膀,一边跟旁边做着推举的同伴抱怨道,”我们有半年没见了吧?好不容易放假了,我立马来找你,你看看你,…

    Python 2022年10月14日
    0117
  • pip相关介绍

    #pip的基础使用 介绍 众所周知,pip可以对python的第三方库进行安装、更新、卸载等操作,十分方便。 pip的全称:package installer for python…

    Python 2023年1月5日
    050
  • YOLOv5算法详解

    1:输入端 (1) Mosaic数据增强 Yolov5的输入端采用了和Yolov4一样的Mosaic数据增强的方式。Mosaic是参考2019年底提出的CutMix数据增强的方式,…

    Python 2022年12月24日
    049
  • 查看python中安装库的文件位置的方法

    安装库位置和显示方式简单总结: 一、位置的不同 1.自带库在环境的 lib\\os.py 2.自己安装库在 lib\\site-packages\\numpy\\__init__….

    Python 2022年12月24日
    049
  • 6 pandas

    处理字符串 时间序列等非数值信息 常用数据类型 series 一维 带标签数组 dataframe 二维数组 6.1 series 本质由两部分构成: 键(索引)+ 值 pd.Se…

    Python 2022年12月30日
    038
  • Django REST framework JWT

    0. 官方已经弃用,不在更新 最新版的django(4x系列)无法在使用jwt, 其开发者推荐的替代品为Simple JWT(djangorestframework-simplej…

    Python 2022年12月27日
    053
  • GMTSAR流程记录

    一 数据获取 二 数据准备 读取SAR文件目录,解压SAR文件 data_unzip.csh 检查是否下完 data_check.csh gmt grdpaste file_a.n…

    Python 2023年2月5日
    038
  • 矩阵的用法Python numpy学习(2)

    相关知识 可能是最全的NumPy基础知识(一) Python矩阵的基本用法 mat()函数将目标数据的类型转化成矩阵(matrix) 1,mat()函数和array()函数的区别 …

    Python 2023年1月13日
    044
  • 作为一名测试人员,如何拾开发者牙慧,开启兼职赚钱之路

    文章目录 * – + 一、赚钱:无论何时何地,它从来都不寒碜 + 二、分析:不要相信解决一个问题就真的只是一个问题 + * 2.1、登录源码:页面跳转 * 2.2、登录…

    Python 2022年12月26日
    038
  • 看我使用Python秒变高级程序员

    抵扣说明: 1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。 Original: https:…

    Python 2023年2月6日
    014
  • python如何做成app?

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 python如何做成app? 一、Python3.8.3版本+kivy1.10.0 二、用命令提示符(可…

    2022年8月28日
    0283
  • python基于django大学生心理健康系统

    通过高校心理咨询系统的设计与实现,应用相应的管理法规,保障管理系统的完整性;提高了管理环境;保障高校心理咨询系统工作正常秩序,确保工作有序进行;提高监督使用者的自觉性,达到宣传教育…

    Python 2022年12月27日
    044
  • 接口自动化(flask框架及接口测试)

    flask框架: 模块:flask 使用步骤: 创建项目:需要在项目中创建的文件 [En] Create a project: files that need to be crea…

    Python 2023年1月6日
    026
  • 第十小组Alpha冲刺(3/3)

    已完成的工作: 1. 学习了flask框架的概念与使用,以将python的深度学习算法部署到web网页中,Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型…

    Python 2023年1月3日
    059
最近整理资源【免费获取】:   👉 程序员最新必读书单  | 👏 互联网各方向面试题下载 | ✌️计算机核心资源汇总