필수 C 번호 [열한] 맞춤 유형 (b)에 조립 참조, XML 주석, 쓰레기 수거 및 청소 자원

이전 섹션의 내용 유형에 맞게 남아있는이 블로그에 소개 한 후 연산자 오버로딩 방법과 개체 방법을 다시 작성하고합니다 :
그림 삽입 설명 여기

어셈블리 참조와 네임 스페이스 정의

이러한 비교적 간단한 내용 중 일부는 너무 많은 예를 들어, 세 개의 인용 방법에 관심을 지불 할 필요가 다른 어셈블리를 참조, 설명되지 않습니다 :

  • 첫 번째 방법은 참조 라이브러리 프로젝트 파일입니다 소스 코드의 라이브러리가있는 프로젝트는 두 개의 프로젝트 사이에 종속성을 설정 지적. 프로그램을 라이브러리를 컴파일하는 데 좋은 참고 라이브러리를 컴파일 후. 종속성은 컴파일러가 (당신이 어떤 컴파일하지 않은 경우) 라이브러리를 컴파일 할 때 발생 프로젝트, 공통의 복사
  • 두 번째 방법은 파일 자체 조립 참조 . 즉, 참조 라이브러리 대신 컴파일 된 프로그램. 회사 내 다른 팀에 의해 컴파일과 같은 라이브러리와 프로그램이 개별적으로 컴파일 된 경우,이 방법은 매우 합리적이다. ( DLL 복사본으로 디버깅 시간)
  • 세 번째 방법은 참조 NuGet 패키지 ( 프로젝트 고급 복사, 라이브러리 NuGet에서 항목을 복사 )

참고 라이브러리 및 패키지에만 콘솔 프로그램에 의해 참조되지 않습니다. 사실, 임의의 어셈블리는 다른 어셈블리를 참조 할 수있다. 종종 라이브러리 참조 다른 라이브러리는 종속성 체인을 만들 . 유형에 따라 액세스 수준에 대해 우려하는 동안 :
그림 삽입 설명 여기
참고 : 접근성의 멤버가 포함되어있는 클래스보다 클 수 없습니다 , (모든 수정을 사용할 수 있습니다 중첩 된 클래스 제외) 클래스는 공공 및 내부 사용할 수 있습니다 . 네임 스페이스는 만 줄에 다음 설계 사양에 지불 관심을 상대적으로 간단 필요가있다 :

  • 네임 스페이스 접두사를 추가로 회사 이름 과 동일한 이름을 사용하는 다른 회사를 방지하기 위해.
  • 하기 위해 네임 스페이스 안정 보조 이름을 사용, 제품 이름의 업그레이드 버전으로 변경되지 않습니다 .
  • 명시 적으로 이름 공간에 유형을 정의하지 마십시오.
  • 공간을 만드는 것을 고려하고 파일 계층 일치하는 폴더 구조를 이름 .

모두 모두 네임 스페이스의 파일에서 최고의 클래스는 클래스를 감싸는 것입니다.

XML 주석

C # 컴파일러는 결과 실행 파일의 모든 의견을 무시하지만 개발자가 사용할 수 있지만 명령 줄 옵션은 컴파일러가 별도의 XML 파일에 XML 주석을 추출  지시합니다. 이것은 XML 주석에서 API 문서를 생성합니다. 또한, C # 1 편집기 코드 XML 코멘트를 분석 할 수 있고, 영역 표시 대상 (예를 들면, 다른 코드로부터 컬러 다른 사용)을 XML 코멘트 표시 현상을 분석하기 위해, 또는 데이터 요소. 당신은 예를 들어, 작업을 표준화 문서화 할 수 있도록 시간이 해결 될 API 문서를 생성하는 매개 변수를 정의
그림 삽입 설명 여기

쓰레기 수거

가비지 콜렉션은 더 이상 메모리를 참조 점유하지 개체의 핵심을 되찾기 위해 설계된 기능 "실행"입니다. **이 문장은 "메모리"와 "참조"에 초점을 맞추고 있습니다 . 회수 메모리 가비지 컬렉터는, 다른 자원을 처리하지 않는 데이터베이스 연결, 핸들 (파일, 창 등), 네트워크 포트, (예 : 시리얼 포트와 같은) 하드웨어 장치로,. 또한, 가비지 컬렉터는 모든 참조가 있는지 여부에 따라하면 청소 원하는 것을 결정합니다. 이 것을 의미 가비지 수집기 핸들만을 회수 힙 메모리 객체에 대한 참조이다. 또한, 개체에 대한 참조를 유지하는 것을 의미하는 경우 외에, 쓰레기 수집기는 객체가 사용되는 메모리의 재사용을 방지한다. **

가비지 수집 알고리즘

닷넷 사용 마크 및 컴팩트 알고리즘 정리를 수행 한 후 정리하고 메모리에 액세스 개체 및 개체를 포함하도록 넣고, 전체 동작 프로세스로 도달 알고리즘을 사용하여 다음된다 :

  1. 가비지 콜렉션주기의 시작에서, 모든 루트 개체를 식별합니다. 루트 정적 변수, CPU 레지스터와 어떤 기준 (F-도달 가능한 객체를 포함) 로컬 변수 또는 매개 변수 실시 예에서 참조 목록에 기초는 가비지 컬렉터 참조로 식별 된 각각의 트리 구조의 루트를 탐색하고, 재귀 모든 루트를 판단 할 객체의 참조 점. 따라서, 모두를 식별 할 수 가비지 컬렉터 접근 할 객체 .
  2. 执行垃圾回收时,垃圾回收器不是枚举所有访问不到的对象;相反,它将所有可达对象紧挨着放到一起,从而覆盖不可访问的对象(也就是垃圾,或者不可达对象)所占用的内存,为定位和移动所有可达对象,系统要在垃圾回收器运行期间维持状态的一致性。为此,进程中的所有托管线程都会在垃圾回收期间暂停。这显然会造成应用程序出现短暂的停顿。不过,除非垃圾回收周期特别长,否则这个停顿是不太引人注意的。为尽量避免在不恰当的时间执行垃圾回收,System.GC对象包含一个**Collect()**方法。可在执行关键代码之前调用它(执行这些代码时不希望GC运行)。这样做不会阻止垃圾回收器运行,但会显著减小它运行的可能性——前提是关键代码执行期间不会发生内存被大量消耗的情况
  3. 发现相较于长期存在的对象,最近创建的对象更有可能需要垃圾回收。为此,.NET垃圾回收器支持“代”(generation)的概念,它会以更快的频率尝试清除生存时间较短的对象(新生对象)。而那些已在一次垃圾回收中“存活”下来的对象(老对象)会以较低的频率清除。具体地说,共有3代对象。一个对象每次在一个垃圾回收周期中存活下来,它都会移动到下一代,直至最终移动到第二代(从第零代开始)。相较于第二代对象,垃圾回收器会以更快的频率对第零代的对象执行垃圾回收

相较于Java的成体系的垃圾回收算法,感觉CLR做的不是很好,也许是没有体系化的了解过吧。

弱引用

弱引用是什么?弱引用就是一直维持的一个引用,但是它并不会组织垃圾回收,为什么要有弱引用呢?这么去想象一下,假如要从数据库加载一个特别大的对象,如果是强引用,一旦用户不再使用该对象,断开引用就需要进行垃圾回收,但假如用户一会儿又想用了,又得重新加载和引用,但如果是弱引用,你可以在保持引用的状态下进行垃圾回收,但在你垃圾回收之前我还是一直保持引用状态,那么假如用户下次请求的时候刚好CLR还没有回收对象,就可以直接获取到对象了,实际上相当于一次内存里的缓存

 public class Program
    {
        private WeakReference Data;

        public FileStream GetData()
        {
            FileStream data = (FileStream)Data.Target;

            if(data != null)
            {
                return data;
            }
            else
            {
                // Load data
                // ...

                // Create a weak reference
                // to data for use later
                Data.Target = data;
            }
            return data;
        }

        public static void Main()
        {
            Console.WriteLine("No output in this example.");
        }
    }

创建弱引用(Data)之后,可查看弱引用是否为null来检查垃圾回收。但这里的关键是先将弱引用赋给一个强引用(FileStream data=Data),避免在“检查null值”和“访问数据”这两个动作之间,垃圾回收器运行并清除弱引用。强引用明显会阻止垃圾回收器清除对象,所以它必须先被赋值(而不是先检查Target是不是为null)

终结器

我们知道垃圾回收器不负责处理除了堆上的引用资源,那么除了内存管理外的一些数据库连接以及句柄等这些资源该怎么释放呢,这个时候就要用到终结器,同时终结器在垃圾回收前也发挥着不可替代的作用(虽然会降低性能,但是能保证对象被延迟清除)

class TemporaryFileStream
    {
        public TemporaryFileStream(string fileName)
        {
            File = new FileInfo(fileName);
            Stream = new FileStream(
                File.FullName, FileMode.OpenOrCreate,
                FileAccess.ReadWrite);
        }

        public TemporaryFileStream()
            : this(Path.GetTempFileName())
        { }

        // Finalizer
        ~TemporaryFileStream()
        {
            Close();
        }

        public FileStream Stream { get; }
        public FileInfo File { get; }

        public void Close()
        {
            Stream?.Dispose();
            File?.Delete();
        }
    }
}

上边这个终结器用来删除文件和关闭流。需要注意的几点是:

  • 终结器不能被显式调用,只能通过垃圾回收器调用,会在对象最后一次使用之后调用,开发人员只能定义不能调用
  • 终结器不允许传递任何参数,不可重载,不可添加访问修饰符

这里的dispose一个对象不是垃圾回收一个对象,而是释放该对象中包装的资源,例如它字段所引用的对象,解除引用,具体的垃圾回收还是需要垃圾回收器的。这里有个漏洞会导致Dispose()执行不了,也就是在实例化TemporaryFileStream后,调用Dispose()前如果发生异常可能不会调用Dispose(),这个时候就要使用确定性终结

 public static void Search()
        {
            using(TemporaryFileStream fileStream1 =
                new TemporaryFileStream(),
                fileStream2 = new TemporaryFileStream())
            {
                // Use temporary file stream;
            }
        }

相当于包裹了一个try finally块。所以实现了终结器的方法的对象的垃圾回收流程是这样的(如果终结器不调用System.GC.SuppressFinalize):整体流程是:先由可达性分析算法把待清理的对象引用放到f-reachable队列里,然后由终结器进行引用终结,终结完成后垃圾回收器才对对象进行垃圾回收。需要注意以下几点:

  • 要只为使用了稀缺或昂贵资源的对象实现终结器方法,即使终结会推迟垃圾回收。
  • 要为有终结器的类实现IDisposable接口以支持确定性终结
  • 要为实现了IDisposable的类实现终结器方法,以防Dispose()没有被显式调用。
  • 要重构终结器方法来调用与IDisposable相同的代码,可能就是调用一下Dispose()方法。
  • 不要在终结器方法中抛出异常
  • 要从Dispose()中调用System.GC.SuppressFinalize(),使垃圾回收更快地发生,并避免重复性的资源清理
  • 要保证Dispose()可以重入(可被多次调用)。
  • 要保持Dispose()的简单性,把重点放在终结所要求的资源清理上。
  • 避免为自己拥有的、带终结器的对象调用Dispose()。相反,依赖终结队列清理实例。
  • 결국 다른 개체 피 참조 프로세스의 끝이 아니다 (자기 부활은 F-도달 큐 외부 참조 됨).
  • 폐기를 다시 작성하는 경우 기본 클래스 구현을 호출하려면 ().
  • 객체가 폐기 () 상태를 호출 한 후 설정을 고려해 사용할 수 없습니다. 오브젝트가 폐기 호출 이외에, 폐기 후 () 메소드 밖에없는 ObjectDisposedException를 발생한다. 예외. (폐기 ()를 여러 번 호출해야합니다.)
  • 구현으로 IDisposable 인터페이스 그 유형의 필드 (또는 속성)를 포함 처분, 이러한 필드를 참조 된 개체를 처리하려면

그런 다음 우리가 더 필요 더 나은하지 초기화 다시 발생할 때 그를 수 있도록했다 물체가 과정을 통해 갈 것입니다 복구하는 방법을 복잡한 볼 수 있습니다 :

 using AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_21;

    class DataCache
    {
        // ...

        public TemporaryFileStream FileStream
        {
            get
            {
                if (_FileStream == null)
                {
                    _FileStream = new TemporaryFileStream();
                }
                return _FileStream;
            }
        }
        private TemporaryFileStream _FileStream = null;

        // ...
    }

TemporaryFileStream로드 된 경우에만하여 FileStream 속성 get 메소드 호출합니다.

어셈블리를로드하는 방법입니다, 사실, 요약하면, 가비지 컬렉션 터미네이터 (소멸자), 자사의 장점과 단점을 수행하는 방법뿐만 아니라, 네임 스페이스 사양을 사용합니다.

게시 된 240 개 원래 기사 · 원 찬양 114 · 전망 180 000 +

추천

출처blog.csdn.net/sinat_33087001/article/details/103844442