java语言中的初始化和垃圾清理

涉及到程序的安全性时,许多程序的错误原因就是源于程序忘记初始化变量。当使用完一个元素时,有很容易忘记释放资源(内存等)。

C++中引入构造器的概念,用于在创建对象时自动调用进行初始化。java也采用构造器,并额外提供了垃圾回收器,对于不再使用的内存资源,垃圾回收器能自动将其释放。


构造器的命名采用与类名相同的名称,这样就避免了与成员名称冲突。在初始化期间要自动调用构造器,这样就顺利成章了。在创建对象时,将会为对象分配存储空间,并且调用相应的构造器,确保你在能够操作对象之前,它已经恰当的初始化了。构造器有助于减少错误,使得代码易于阅读。概念上讲初始化与创建时两个独立的过程,但是在java中,初始化和创建捆版在一起,不能分离。构造器时一种特殊的方法,没有返回值。


如果自定义了一个有参构造器,如 Apple(int num),并且此时没有定义无参构造器,这时候使用new Apple(),编译器会报错。



清理出来和垃圾回收:

一般情况下,java有垃圾回收器负责回收无用对象占据的内存资源,但是也有特殊情况:假定你的对象并非使用new获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放哪些由new 分配的内存,所以它不知道该如何释放这块特殊内存,为了应付这种情况,java允许在类中定义一个finalize()的方法。它的工作原理是这样的:一旦垃圾回收器准备释放对象占用的空间,将首先调用其finalize()方法,并且在下一次回收动作发生时,才会真正回收对象占用的内存,所以如果要是打算用finalize(),就能在垃圾回收的时候做一些重要的工作。 和C++相比,java里的对象并非总是被垃圾回收: 对象可能不会被垃圾回收;垃圾回收不等于“析构”,垃圾回收只与内存有关。

不能把finalize()作为通用的清理方法。垃圾回收只与内存有关,使用垃圾回收器的唯一原因是为了回收程序不再使用的内存。所以对于所有与垃圾回收相关的任何行为来说(尤其是finalize方法),它们也必须同内存及其回收相关。这就使得finalize()作用的场景限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。之所以要有finalize(),是由于在分配内存时可能采用了类似C语言中的做法,而非java中的做法。本地方法是一种在java中调用非java代码的方式,目前只支持C和C++,在非java代码中,也许会调用C的malloc()函数系列来分配存储空间,而且除非是free()函数,否则存储空间得不到释放,从而造成内存泄露。所以需要在finalize()中用本地方法去调用它。


垃圾回收器的工作方式

在以前学过的程序语言中,在堆上分配对象的代价十分高昂,因此读者自然会觉得java中所有对象都在堆上分配的方式也非常高昂。然而,垃圾回收器对于提高对象的创建速度,却具有明显的效果。java虚拟机的工作方式,使得存储空间的释放会影响存储空间的分配。这意味着,java从堆分配空间的速度,可以和其他语言从堆栈上分配空间的速度相媲美。在某些java虚拟机中,堆的实现截然不同,它更像是一个传送带,每分配一个新对象,它就往前移动一格。这意味着对象存储空间分配速度非常快。java的堆指针只是简单移动到尚未分配的区域,其效率比得上C++在堆栈上分配空间的效率。


在想更换的理解java中的垃圾回收,先了解其他系统的垃圾回收机制。引用计数是一种简单但速度很慢的垃圾回收技术,每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加1。当引用离开作用域或被置为null时,引用计数器减1.虽然管理引用数的开销不大,但这项开销在整个程序的生命周期中将持续发生。垃圾回收会在含有全部对象的列表上遍历,当发现某个对象的引用计数为0时,就释放其占用的空间(经常会有在计数值为0时立即释放对象)。这种方法有个缺陷,如果对象之间存在循环引用,就会出现对象应该被收回,但是引用计数却不为0的情况。引用计数常用来说明垃圾收集的方式,但是基本不用于任何一种java虚拟机的实现。

在一些更快的模式中,垃圾回收器依据的思想是:对任何“活”的对象,一定能够追溯到其存活在堆栈或者静态存储区之中的引用。这个引用链条可能穿过数个对象层次。由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有的活的对象。对于发现的每一个引用,必须追踪它所引用的对象,然后是此对象包含的全部引用。如此反复进行,知道根源于堆栈和静态存储区域的引用所形成的网络全部被访问为止。所访问过的对象必须全部是活的。

在以上 这种方式下,jav虚拟机采用了一种自适应的垃圾回收技术。至于如何处理找到的存活的对象,取决于不同的java虚拟机实现。有一种做法名为:停止——复制,这意味着先暂停程序的运行,然后将所有存活的对象从当前对复制到新堆中保持紧凑排列,然后分配新空间了。当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正。位于堆或者静态存储区域的引用可以直接被修正,但可能还有指向这些对象的引用,它们在遍历的过程中才能被找到。 这种复制式回收器的效率会降低,首先因为它需要两个堆,然后在这个分离的堆上来回倒腾,从而维护比实际需要多一倍的空间。某些java虚拟机的处理方式就是在堆中分配几块较大的内存,复制动作发生在这些较大的内存上。第二个问题在于复制,程序进入稳定状态后,可能只会产生少量垃圾,甚至没有垃圾,尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费。为了解决这种情况,一些java虚拟机会进行检查,要是没有新垃圾产生,就会转移到另一种工作模式(自适应)。这种模式称为标记——清扫。这种方式相当慢,但是当你知道只会产生少量垃圾的时候它的速度就快了。这种模式所依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,进而找到所有存活的对象。每当它找到一个存活对象,就会给对象一个标记,这个过程不会回收任何对象,只有当全部标记工作完成时,清理动作才开始,在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。所以剩下的空间是不连续的,垃圾回收是要希望得到连续空间的话,就得重新整理剩下的对象。


“自适应、分代的、停止---复制、标记---清扫”式垃圾回收器。


java虚拟机中有许多附加技术提升速度,尤其是与加载操作相关的,被称为"及时:just—in—time, JIT"编译器的技术。这种技术可以把程序全部或者部分翻译为本地机器码,程序运行速度因此提升。当需要装载某个类(通常是在为该类创建第一个对象)时,编译器就会先找到.class文件,然后将该类的字节码装入内存,如果采用惰性评估的做法,只在必要的时候才编译代码,这样,从不被执行的代码也许就压根不会被JIT所编译。代码每次被执行的时候都会做一些优化,所以执行的次数越多,它的速度越快。



无法阻止程序自动初始化的进行,它在构造器被调用前发生。

在类的内部,变量定义的先后顺序决定了初始化顺序。即使变量定义散步在方法定义之间,它们仍然会在任何地方被调用之前得到初始化。

无论创建多少个对象。静态数据都只占一份存储区域。static关键字不能用与局部变量,因为它只能作用于域。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统,可以是移动应用、网页服务或集成到智能农业设备。 7. **实时监测**:在实际应用,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值